Merge pull request #8 from myrle-krantz/develop

Initialization via permitted-feign-client.
diff --git a/component-test/src/main/java/io/mifos/provisioner/tenant/Fixture.java b/component-test/src/main/java/io/mifos/provisioner/tenant/Fixture.java
index a7cf7f2..eb457f9 100644
--- a/component-test/src/main/java/io/mifos/provisioner/tenant/Fixture.java
+++ b/component-test/src/main/java/io/mifos/provisioner/tenant/Fixture.java
@@ -16,20 +16,17 @@
 package io.mifos.provisioner.tenant;
 
 
+import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.provisioner.api.v1.domain.CassandraConnectionInfo;
 import io.mifos.provisioner.api.v1.domain.DatabaseConnectionInfo;
 import io.mifos.provisioner.api.v1.domain.Tenant;
 
 class Fixture {
-
-  private static Tenant compTestTenant = new Tenant();
-
-  static final String TENANT_IDENTIFIER = "comp-test";
-
   static final String TENANT_NAME = "Comp Test";
 
-  static {
-    compTestTenant.setIdentifier(TENANT_IDENTIFIER);
+  static Tenant getCompTestTenant() {
+    final Tenant compTestTenant = new Tenant();
+    compTestTenant.setIdentifier(TestEnvironment.getRandomTenantName());
     compTestTenant.setName(TENANT_NAME);
     compTestTenant.setDescription("Component Test Tenant");
 
@@ -49,9 +46,7 @@
     databaseConnectionInfo.setPort("3306");
     databaseConnectionInfo.setUser("root");
     databaseConnectionInfo.setPassword("mysql");
-  }
 
-  static Tenant getCompTestTenant() {
     return compTestTenant;
   }
 }
diff --git a/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenantApplicationAssignment.java b/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenantApplicationAssignment.java
index 6375a2c..9b46af3 100644
--- a/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenantApplicationAssignment.java
+++ b/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenantApplicationAssignment.java
@@ -16,6 +16,7 @@
 package io.mifos.provisioner.tenant;
 
 import io.mifos.anubis.api.v1.client.Anubis;
+import io.mifos.anubis.api.v1.domain.AllowedOperation;
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.PermittableEndpoint;
 import io.mifos.anubis.api.v1.domain.Signature;
@@ -29,7 +30,11 @@
 import io.mifos.core.lang.security.RsaKeyPairFactory;
 import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.identity.api.v1.client.IdentityManager;
+import io.mifos.identity.api.v1.domain.CallEndpointSet;
+import io.mifos.identity.api.v1.domain.Permission;
 import io.mifos.identity.api.v1.domain.PermittableGroup;
+import io.mifos.permittedfeignclient.api.v1.client.ApplicationPermissionRequirements;
+import io.mifos.permittedfeignclient.api.v1.domain.ApplicationPermission;
 import io.mifos.provisioner.ProvisionerCassandraInitializer;
 import io.mifos.provisioner.ProvisionerMariaDBInitializer;
 import io.mifos.provisioner.api.v1.client.Provisioner;
@@ -175,18 +180,24 @@
     private final String keyTimestamp;
     private final BigInteger modulus;
     private final BigInteger exponent;
+    private final String tenantIdentifier;
 
     private boolean validSecurityContext = false;
 
-    VerifyIsisInitializeContext(final String keyTimestamp, final BigInteger modulus, final BigInteger exponent) {
+    VerifyIsisInitializeContext(
+            final String keyTimestamp,
+            final BigInteger modulus,
+            final BigInteger exponent,
+            final String tenantIdentifier) {
       this.keyTimestamp = keyTimestamp;
       this.modulus = modulus;
       this.exponent = exponent;
+      this.tenantIdentifier = tenantIdentifier;
     }
 
     @Override
     public ApplicationSignatureSet answer(final InvocationOnMock invocation) throws Throwable {
-      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext("identity", "1", Fixture.TENANT_IDENTIFIER);
+      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext("identity", "1", tenantIdentifier);
 
       final Signature fakeSignature = new Signature();
       fakeSignature.setPublicKeyMod(modulus);
@@ -209,14 +220,16 @@
 
     private boolean validSecurityContext = false;
     final private String target;
+    private final String tenantIdentifier;
 
-    private VerifyAnubisInitializeContext(final String target) {
+    private VerifyAnubisInitializeContext(final String target, String tenantIdentifier) {
       this.target = target;
+      this.tenantIdentifier = tenantIdentifier;
     }
 
     @Override
     public Void answer(final InvocationOnMock invocation) throws Throwable {
-      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext(target, "1", Fixture.TENANT_IDENTIFIER);
+      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext(target, "1", tenantIdentifier);
       return null;
     }
 
@@ -227,22 +240,26 @@
 
   private class VerifyCreateSignatureSetContext implements Answer<ApplicationSignatureSet> {
 
+    private final RsaKeyPairFactory.KeyPairHolder answer;
     private boolean validSecurityContext = false;
     final private String target;
+    private final String tenantIdentifier;
 
-    private VerifyCreateSignatureSetContext(final String target) {
+    private VerifyCreateSignatureSetContext(final RsaKeyPairFactory.KeyPairHolder answer, final String target, final String tenantIdentifier) {
+      this.answer = answer;
       this.target = target;
+      this.tenantIdentifier = tenantIdentifier;
     }
 
     @Override
     public ApplicationSignatureSet answer(final InvocationOnMock invocation) throws Throwable {
       final String timestamp = invocation.getArgumentAt(0, String.class);
       final Signature identityManagerSignature = invocation.getArgumentAt(1, Signature.class);
-      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext(target, "1", Fixture.TENANT_IDENTIFIER);
-      final RsaKeyPairFactory.KeyPairHolder keys = RsaKeyPairFactory.createKeyPair();
+      validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext(target, "1", tenantIdentifier);
+
       return new ApplicationSignatureSet(
               timestamp,
-              new Signature(keys.getPublicKeyMod(), keys.getPublicKeyExp()),
+              new Signature(answer.getPublicKeyMod(), answer.getPublicKeyExp()),
               identityManagerSignature);
     }
 
@@ -256,14 +273,39 @@
 
     private boolean validSecurityContext = false;
     private final List<PermittableEndpoint> answer;
+    private final String tenantIdentifier;
 
-    private VerifyAnubisPermittablesContext(final List<PermittableEndpoint> answer) {
+    private VerifyAnubisPermittablesContext(final List<PermittableEndpoint> answer, final String tenantIdentifier) {
       this.answer = answer;
+      this.tenantIdentifier = tenantIdentifier;
     }
 
     @Override
     public List<PermittableEndpoint> answer(final InvocationOnMock invocation) throws Throwable {
-      validSecurityContext = systemSecurityEnvironment.isValidGuestSecurityContext(Fixture.TENANT_IDENTIFIER);
+      validSecurityContext = systemSecurityEnvironment.isValidGuestSecurityContext(tenantIdentifier);
+      return answer;
+    }
+
+    boolean isValidSecurityContext() {
+      return validSecurityContext;
+    }
+  }
+
+
+  private class VerifyAnputRequiredPermissionsContext implements Answer<List<ApplicationPermission>> {
+
+    private boolean validSecurityContext = false;
+    private final List<ApplicationPermission> answer;
+    private final String tenantIdentifier;
+
+    private VerifyAnputRequiredPermissionsContext(final List<ApplicationPermission> answer, final String tenantIdentifier) {
+      this.answer = answer;
+      this.tenantIdentifier = tenantIdentifier;
+    }
+
+    @Override
+    public List<ApplicationPermission> answer(final InvocationOnMock invocation) throws Throwable {
+      validSecurityContext = systemSecurityEnvironment.isValidGuestSecurityContext(tenantIdentifier);
       return answer;
     }
 
@@ -298,16 +340,16 @@
     when(applicationCallContextProviderSpy.getApplication(IdentityManager.class, "http://xyz.identity:2020/v1")).thenReturn(identityServiceMock);
 
     final VerifyIsisInitializeContext verifyInitializeContextAndReturnSignature;
-    try (final AutoTenantContext ignored = new AutoTenantContext(Fixture.TENANT_IDENTIFIER)) {
+    try (final AutoTenantContext ignored = new AutoTenantContext(tenant.getIdentifier())) {
       verifyInitializeContextAndReturnSignature = new VerifyIsisInitializeContext(
               systemSecurityEnvironment.tenantKeyTimestamp(),
               systemSecurityEnvironment.tenantPublicKey().getModulus(),
-              systemSecurityEnvironment.tenantPublicKey().getPublicExponent());
+              systemSecurityEnvironment.tenantPublicKey().getPublicExponent(), tenant.getIdentifier());
     }
     doAnswer(verifyInitializeContextAndReturnSignature).when(identityServiceMock).initialize(anyString());
 
     final TokenChecker tokenChecker = new TokenChecker();
-    doAnswer(tokenChecker).when(tokenProviderSpy).createToken(Fixture.TENANT_IDENTIFIER, "identity-v1", 2L, TimeUnit.MINUTES);
+    doAnswer(tokenChecker).when(tokenProviderSpy).createToken(tenant.getIdentifier(), "identity-v1", 2L, TimeUnit.MINUTES);
 
     {
       final IdentityManagerInitialization identityServiceAdminInitialization
@@ -318,7 +360,7 @@
       Assert.assertNotNull(identityServiceAdminInitialization.getAdminPassword());
     }
 
-    verify(applicationCallContextProviderSpy, atMost(2)).getApplicationCallContext(Fixture.TENANT_IDENTIFIER, "identity-v1");
+    verify(applicationCallContextProviderSpy, atMost(2)).getApplicationCallContext(tenant.getIdentifier(), "identity-v1");
 
 
     //Create horus application.
@@ -338,38 +380,60 @@
     final Anubis anubisMock = Mockito.mock(Anubis.class);
     when(applicationCallContextProviderSpy.getApplication(Anubis.class, "http://xyz.office:2021/v1")).thenReturn(anubisMock);
 
+    final ApplicationPermissionRequirements anputMock = Mockito.mock(ApplicationPermissionRequirements.class);
+    when(applicationCallContextProviderSpy.getApplication(ApplicationPermissionRequirements.class, "http://xyz.office:2021/v1")).thenReturn(anputMock);
+
+    final RsaKeyPairFactory.KeyPairHolder keysInApplicationSignature = RsaKeyPairFactory.createKeyPair();
 
     final PermittableEndpoint xxPermittableEndpoint = new PermittableEndpoint("/x/y", "POST", "x");
     final PermittableEndpoint xyPermittableEndpoint = new PermittableEndpoint("/y/z", "POST", "x");
     final PermittableEndpoint xyGetPermittableEndpoint = new PermittableEndpoint("/y/z", "GET", "x");
     final PermittableEndpoint mPermittableEndpoint = new PermittableEndpoint("/m/n", "GET", "m");
 
+    final ApplicationPermission forFooPermission = new ApplicationPermission("forPurposeFoo", new Permission("x", AllowedOperation.ALL));
+    final ApplicationPermission forBarPermission = new ApplicationPermission("forPurposeBar", new Permission("m", Collections.singleton(AllowedOperation.READ)));
+
     final VerifyAnubisInitializeContext verifyAnubisInitializeContext;
     final VerifyCreateSignatureSetContext verifyCreateSignatureSetContext;
     final VerifyAnubisPermittablesContext verifyAnubisPermittablesContext;
-    try (final AutoTenantContext ignored = new AutoTenantContext(Fixture.TENANT_IDENTIFIER)) {
-      verifyAnubisInitializeContext = new VerifyAnubisInitializeContext("office");
-      verifyCreateSignatureSetContext = new VerifyCreateSignatureSetContext("office");
-      verifyAnubisPermittablesContext = new VerifyAnubisPermittablesContext(Arrays.asList(xxPermittableEndpoint, xxPermittableEndpoint, xyPermittableEndpoint, xyGetPermittableEndpoint, mPermittableEndpoint));
+    final VerifyAnputRequiredPermissionsContext verifyAnputRequiredPermissionsContext;
+    try (final AutoTenantContext ignored = new AutoTenantContext(tenant.getIdentifier())) {
+      verifyAnubisInitializeContext = new VerifyAnubisInitializeContext("office", tenant.getIdentifier());
+      verifyCreateSignatureSetContext = new VerifyCreateSignatureSetContext(keysInApplicationSignature, "office", tenant.getIdentifier());
+      verifyAnubisPermittablesContext = new VerifyAnubisPermittablesContext(Arrays.asList(xxPermittableEndpoint, xxPermittableEndpoint, xyPermittableEndpoint, xyGetPermittableEndpoint, mPermittableEndpoint), tenant.getIdentifier());
+      verifyAnputRequiredPermissionsContext = new VerifyAnputRequiredPermissionsContext(Arrays.asList(forFooPermission, forBarPermission), tenant.getIdentifier());
     }
     doAnswer(verifyAnubisInitializeContext).when(anubisMock).initializeResources();
     doAnswer(verifyCreateSignatureSetContext).when(anubisMock).createSignatureSet(anyString(), anyObject());
     doAnswer(verifyAnubisPermittablesContext).when(anubisMock).getPermittableEndpoints();
+    doAnswer(verifyAnputRequiredPermissionsContext).when(anputMock).getRequiredPermissions();
+
 
     {
       provisioner.assignApplications(tenant.getIdentifier(), Collections.singletonList(officeAssigned));
-      Thread.sleep(500L); //Application assigning is asynchronous.
+      Thread.sleep(1500L); //Application assigning is asynchronous and I have no message queue.
     }
 
-    verify(applicationCallContextProviderSpy).getApplicationCallContext(Fixture.TENANT_IDENTIFIER, "office-v1");
+    verify(applicationCallContextProviderSpy).getApplicationCallContext(tenant.getIdentifier(), "office-v1");
     verify(applicationCallContextProviderSpy, never()).getApplicationCallContext(eq(Fixture.TENANT_NAME), Mockito.anyString());
-    verify(tokenProviderSpy).createToken(Fixture.TENANT_IDENTIFIER, "office-v1", 2L, TimeUnit.MINUTES);
+    verify(tokenProviderSpy).createToken(tenant.getIdentifier(), "office-v1", 2L, TimeUnit.MINUTES);
 
-    verify(identityServiceMock).createPermittableGroup(new PermittableGroup("x", Arrays.asList(xxPermittableEndpoint, xyPermittableEndpoint, xyGetPermittableEndpoint)));
-    verify(identityServiceMock).createPermittableGroup(new PermittableGroup("m", Collections.singletonList(mPermittableEndpoint)));
+    try (final AutoTenantContext ignored = new AutoTenantContext(tenant.getIdentifier())) {
+      verify(identityServiceMock).setApplicationSignature(
+              "office-v1",
+              systemSecurityEnvironment.tenantKeyTimestamp(),
+              new Signature(keysInApplicationSignature.getPublicKeyMod(), keysInApplicationSignature.getPublicKeyExp()));
+      verify(identityServiceMock).createPermittableGroup(new PermittableGroup("x", Arrays.asList(xxPermittableEndpoint, xyPermittableEndpoint, xyGetPermittableEndpoint)));
+      verify(identityServiceMock).createPermittableGroup(new PermittableGroup("m", Collections.singletonList(mPermittableEndpoint)));
+      verify(identityServiceMock).createApplicationPermission("office-v1", new Permission("x", AllowedOperation.ALL));
+      verify(identityServiceMock).createApplicationPermission("office-v1", new Permission("m", Collections.singleton(AllowedOperation.READ)));
+      verify(identityServiceMock).createApplicationCallEndpointSet("office-v1", new CallEndpointSet("forPurposeFoo", Collections.singletonList("x")));
+      verify(identityServiceMock).createApplicationCallEndpointSet("office-v1", new CallEndpointSet("forPurposeBar", Collections.singletonList("m")));
+    }
 
     Assert.assertTrue(verifyAnubisInitializeContext.isValidSecurityContext());
     Assert.assertTrue(verifyCreateSignatureSetContext.isValidSecurityContext());
     Assert.assertTrue(verifyAnubisPermittablesContext.isValidSecurityContext());
+    Assert.assertTrue(verifyAnputRequiredPermissionsContext.isValidSecurityContext());
   }
 }
diff --git a/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenants.java b/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenants.java
index 73d8af8..2fade74 100644
--- a/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenants.java
+++ b/component-test/src/main/java/io/mifos/provisioner/tenant/TestTenants.java
@@ -48,7 +48,6 @@
   @After
   public void after() throws InterruptedException {
     provisioner.deleteTenant(Fixture.getCompTestTenant().getIdentifier());
-    Thread.sleep(1200L);
     autoSeshat.close();
   }
 
diff --git a/service/build.gradle b/service/build.gradle
index fea755c..edb1055 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -33,6 +33,7 @@
             [group: 'io.mifos.provisioner', name: 'api', version: project.version],
             [group: 'io.mifos.anubis', name: 'library', version: versions.frameworkanubis],
             [group: 'io.mifos.anubis', name: 'api', version: versions.frameworkanubis],
+            [group: 'io.mifos.permitted-feign-client', name: 'api', version: versions.frameworkanput],
             [group: 'io.mifos.identity', name: 'api', version: versions.mifosidentityservice],
             [group: 'com.google.code.gson', name: 'gson', version: versions.gson],
             [group: 'io.mifos.core', name: 'api', version: versions.frameworkapi],
diff --git a/service/src/main/java/io/mifos/provisioner/internal/repository/TenantCassandraRepository.java b/service/src/main/java/io/mifos/provisioner/internal/repository/TenantCassandraRepository.java
index bbc1b84..7294702 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/repository/TenantCassandraRepository.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/repository/TenantCassandraRepository.java
@@ -21,6 +21,7 @@
 import com.datastax.driver.core.PlainTextAuthProvider;
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Session;
+import com.datastax.driver.core.exceptions.AlreadyExistsException;
 import com.datastax.driver.core.schemabuilder.SchemaBuilder;
 import com.datastax.driver.mapping.Mapper;
 import com.datastax.driver.mapping.MappingManager;
@@ -102,10 +103,15 @@
       throw ServiceException.conflict("Tenant {0} already exists!", tenant.getIdentifier());
     }
     final Session session = this.getCluster(tenant).connect();
-    session.execute("CREATE KEYSPACE " + tenant.getKeyspaceName() + " WITH REPLICATION = " +
-            ReplicationStrategyResolver.replicationStrategy(
-                    tenant.getReplicationType(),
-                    tenant.getReplicas()));
+    try {
+      session.execute("CREATE KEYSPACE " + tenant.getKeyspaceName() + " WITH REPLICATION = " +
+              ReplicationStrategyResolver.replicationStrategy(
+                      tenant.getReplicationType(),
+                      tenant.getReplicas()));
+    }
+    catch (final AlreadyExistsException e) {
+      throw ServiceException.conflict("Tenant {0} already exists!", tenant.getIdentifier());
+    }
 
     final String createCommandSourceTable =
             SchemaBuilder.createTable(tenant.getKeyspaceName(), "command_source")
diff --git a/service/src/main/java/io/mifos/provisioner/internal/service/TenantApplicationService.java b/service/src/main/java/io/mifos/provisioner/internal/service/TenantApplicationService.java
index 6ac79ff..149f062 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/service/TenantApplicationService.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/service/TenantApplicationService.java
@@ -19,7 +19,6 @@
 import com.datastax.driver.mapping.Mapper;
 import com.datastax.driver.mapping.Result;
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
-import io.mifos.anubis.api.v1.domain.Signature;
 import io.mifos.anubis.config.TenantSignatureRepository;
 import io.mifos.core.cassandra.core.CassandraSessionProvider;
 import io.mifos.core.lang.AutoTenantContext;
@@ -70,22 +69,39 @@
     Assert.notNull(tenantApplicationEntity);
     Assert.notNull(appNameToUriMap);
 
-    final Optional<TenantEntity> tenantEntity = tenantCassandraRepository.get(tenantApplicationEntity.getTenantIdentifier());
-    tenantEntity.ifPresent(x -> {
-      checkApplications(tenantApplicationEntity.getApplications());
+    final TenantEntity tenantEntity = tenantCassandraRepository.get(tenantApplicationEntity.getTenantIdentifier())
+            .orElseThrow(() -> ServiceException.notFound("Tenant {0} not found.", tenantApplicationEntity.getTenantIdentifier()));
 
-      saveTenantApplicationAssignment(tenantApplicationEntity);
+    checkApplicationsExist(tenantApplicationEntity.getApplications());
 
-      final Set<ApplicationNameToUriPair> applicationNameToUriPairs =
-              getApplicationNameToUriPairs(tenantApplicationEntity, appNameToUriMap);
+    saveTenantApplicationAssignment(tenantApplicationEntity);
 
-      initializeIsis(x, applicationNameToUriPairs);
+    final Set<ApplicationNameToUriPair> applicationNameToUriPairs =
+            getApplicationNameToUriPairs(tenantApplicationEntity, appNameToUriMap);
 
-      getLatestIdentityManagerSignatureSet(x).ifPresent(y -> initializeAnubis(x, y.getTimestamp(), y.getIdentityManagerSignature(), applicationNameToUriPairs));
+    getLatestIdentityManagerSignatureSet(tenantEntity)
+            .ifPresent(y -> initializeSecurity(tenantEntity, y, applicationNameToUriPairs));
+  }
+
+  private void initializeSecurity(final TenantEntity tenantEntity,
+                                  final ApplicationSignatureSet identityManagerSignatureSet,
+                                  final Set<ApplicationNameToUriPair> applicationNameToUriPairs) {
+    applicationNameToUriPairs.forEach(x -> {
+      final ApplicationSignatureSet applicationSignatureSet = anubisInitializer.initializeAnubis(
+              tenantEntity.getIdentifier(),
+              x.name,
+              x.uri,
+              identityManagerSignatureSet.getTimestamp(),
+              identityManagerSignatureSet.getIdentityManagerSignature());
+
+      identityServiceInitializer.postApplicationDetails(
+              tenantEntity.getIdentifier(),
+              tenantEntity.getIdentityManagerApplicationName(),
+              tenantEntity.getIdentityManagerApplicationUri(),
+              x.name,
+              x.uri,
+              applicationSignatureSet);
     });
-
-    tenantEntity.orElseThrow(
-            () -> ServiceException.notFound("Tenant {0} not found.", tenantApplicationEntity.getTenantIdentifier()));
   }
 
   private void saveTenantApplicationAssignment(final @Nonnull TenantApplicationEntity tenantApplicationEntity) {
@@ -134,32 +150,6 @@
     }
   }
 
-  private void initializeIsis(
-          final @Nonnull TenantEntity tenantEntity,
-          final @Nonnull Set<ApplicationNameToUriPair> applicationNameToUriPairs) {
-    applicationNameToUriPairs.forEach(applicationNameUriPair ->
-            identityServiceInitializer.postPermittableGroups(
-                    tenantEntity.getIdentifier(),
-                    tenantEntity.getIdentityManagerApplicationName(),
-                    tenantEntity.getIdentityManagerApplicationUri(),
-                    applicationNameUriPair.uri));
-  }
-
-  private void initializeAnubis(
-          final @Nonnull TenantEntity tenantEntity,
-          final @Nonnull String keyTimestamp,
-          final @Nonnull Signature identityServiceTenantSignature,
-          final @Nonnull Set<ApplicationNameToUriPair> applicationNameToUriPairs) {
-    applicationNameToUriPairs.forEach(applicationNameUriPair ->
-            anubisInitializer.initializeAnubis(
-                    tenantEntity.getIdentifier(),
-                    applicationNameUriPair.name,
-                    applicationNameUriPair.uri,
-                    keyTimestamp,
-                    identityServiceTenantSignature)
-    );
-  }
-
   public TenantApplicationEntity find(final String tenantIdentifier) {
     checkTenant(tenantIdentifier);
 
@@ -195,7 +185,7 @@
     }
   }
 
-  private void checkApplications(final Set<String> applications) {
+  private void checkApplicationsExist(final Set<String> applications) {
     final Mapper<ApplicationEntity> applicationEntityMapper =
             this.cassandraSessionProvider.getAdminSessionMappingManager().mapper(ApplicationEntity.class);
 
diff --git a/service/src/main/java/io/mifos/provisioner/internal/service/applications/AnubisInitializer.java b/service/src/main/java/io/mifos/provisioner/internal/service/applications/AnubisInitializer.java
index c30876e..657923d 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/service/applications/AnubisInitializer.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/service/applications/AnubisInitializer.java
@@ -16,12 +16,12 @@
 package io.mifos.provisioner.internal.service.applications;
 
 import io.mifos.anubis.api.v1.client.Anubis;
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.Signature;
 import io.mifos.provisioner.config.ProvisionerConstants;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Nonnull;
@@ -42,20 +42,20 @@
     this.logger = logger;
   }
 
-  @Async
-  public void initializeAnubis(final @Nonnull String tenantIdentifier,
-                               final @Nonnull String applicationName,
-                               final @Nonnull String uri,
-                               final @Nonnull String keyTimestamp,
-                               final @Nonnull Signature signature) {
+  public ApplicationSignatureSet initializeAnubis(final @Nonnull String tenantIdentifier,
+                                                  final @Nonnull String applicationName,
+                                                  final @Nonnull String uri,
+                                                  final @Nonnull String keyTimestamp,
+                                                  final @Nonnull Signature signature) {
     try (final AutoCloseable ignored
                  = this.applicationCallContextProvider.getApplicationCallContext(tenantIdentifier, applicationName))
     {
       final Anubis anubis = this.applicationCallContextProvider.getApplication(Anubis.class, uri);
-      anubis.createSignatureSet(keyTimestamp, signature);
       anubis.initializeResources();
-      logger.info("Anubis initialization for io.mifos.provisioner.tenant '{}' and application '{}' succeeded with signature '{}'.",
-              tenantIdentifier, applicationName, signature);
+      final ApplicationSignatureSet applicationSignatureSet = anubis.createSignatureSet(keyTimestamp, signature);
+      logger.info("Anubis initialization for io.mifos.provisioner.tenant '{}' and application '{}' succeeded with signature set '{}'.",
+              tenantIdentifier, applicationName, applicationSignatureSet);
+      return applicationSignatureSet;
 
     } catch (final Exception e) {
       throw new IllegalStateException(e);
diff --git a/service/src/main/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializer.java b/service/src/main/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializer.java
index 7df8945..a2b24db 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializer.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializer.java
@@ -17,14 +17,18 @@
 
 
 import io.mifos.anubis.api.v1.client.Anubis;
+import io.mifos.anubis.api.v1.domain.AllowedOperation;
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.PermittableEndpoint;
 import io.mifos.core.api.util.InvalidTokenException;
 import io.mifos.core.lang.ServiceException;
-import io.mifos.identity.api.v1.client.IdentityManager;
-import io.mifos.identity.api.v1.client.PermittableGroupAlreadyExistsException;
-import io.mifos.identity.api.v1.client.TenantAlreadyInitializedException;
+import io.mifos.core.lang.TenantContextHolder;
+import io.mifos.identity.api.v1.client.*;
+import io.mifos.identity.api.v1.domain.CallEndpointSet;
+import io.mifos.identity.api.v1.domain.Permission;
 import io.mifos.identity.api.v1.domain.PermittableGroup;
+import io.mifos.permittedfeignclient.api.v1.client.ApplicationPermissionRequirements;
+import io.mifos.permittedfeignclient.api.v1.domain.ApplicationPermission;
 import io.mifos.provisioner.config.ProvisionerConstants;
 import io.mifos.tool.crypto.HashGenerator;
 import org.apache.commons.lang.RandomStringUtils;
@@ -38,6 +42,7 @@
 import javax.annotation.Nonnull;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author Myrle Krantz
@@ -123,15 +128,20 @@
     }
   }
 
-  public void postPermittableGroups(
+  public void postApplicationDetails(
           final @Nonnull String tenantIdentifier,
           final @Nonnull String identityManagerApplicationName,
           final @Nonnull String identityManagerApplicationUri,
-          final @Nonnull String applicationUri)
+          final @Nonnull String applicationName,
+          final @Nonnull String applicationUri,
+          final @Nonnull ApplicationSignatureSet applicationSignatureSet)
   {
     final List<PermittableEndpoint> permittables;
+    final List<ApplicationPermission> applicationPermissionRequirements;
     try (final AutoCloseable ignored = applicationCallContextProvider.getApplicationCallGuestContext(tenantIdentifier)) {
       permittables = getPermittables(applicationUri);
+      applicationPermissionRequirements = getApplicationPermissionRequirements(applicationName, applicationUri);
+
     } catch (final Exception e) {
       throw new IllegalStateException(e);
     }
@@ -140,10 +150,16 @@
                  = applicationCallContextProvider.getApplicationCallContext(tenantIdentifier, identityManagerApplicationName))
     {
       final IdentityManager identityService = applicationCallContextProvider.getApplication(IdentityManager.class, identityManagerApplicationUri);
+      identityService.setApplicationSignature(applicationName, applicationSignatureSet.getTimestamp(), applicationSignatureSet.getApplicationSignature());
+      //TODO: I need to know when this is done.  ActiveMQ.  sigh.
 
-      final List<PermittableGroup> permittableGroups = getPermittableGroups(permittables);
-
+      final Stream<PermittableGroup> permittableGroups = getPermittableGroups(permittables);
       permittableGroups.forEach(x -> createOrFindPermittableGroup(identityService, x));
+
+      applicationPermissionRequirements.forEach(x -> createOrFindApplicationPermission(identityService, applicationName, x));
+
+      final Stream<CallEndpointSet> callEndpoints = getCallEndpointSets(applicationPermissionRequirements);
+      callEndpoints.forEach(x -> createOrFindApplicationCallEndpointSet(identityService, applicationName, x));
     } catch (final Exception e) {
       throw new IllegalStateException(e);
     }
@@ -162,15 +178,44 @@
     }
   }
 
-  static List<PermittableGroup> getPermittableGroups(final @Nonnull List<PermittableEndpoint> permittables)
+  private List<ApplicationPermission> getApplicationPermissionRequirements(final @Nonnull String applicationName,
+                                                                           final @Nonnull String applicationUri)
+  {
+    try {
+      final ApplicationPermissionRequirements anput
+              = this.applicationCallContextProvider.getApplication(ApplicationPermissionRequirements.class, applicationUri);
+      return anput.getRequiredPermissions();
+    }
+    catch (final RuntimeException unexpected)
+    {
+      logger.info("Get Required Permissions from application '{}' failed.", applicationName);
+      return Collections.emptyList();
+    }
+  }
+
+  static Stream<PermittableGroup> getPermittableGroups(final @Nonnull List<PermittableEndpoint> permittables)
   {
     final Map<String, Set<PermittableEndpoint>> groupedPermittables = new HashMap<>();
 
     permittables.forEach(x -> groupedPermittables.computeIfAbsent(x.getGroupId(), y -> new LinkedHashSet<>()).add(x));
 
     return groupedPermittables.entrySet().stream()
-            .map(entry -> new PermittableGroup(entry.getKey(), entry.getValue().stream().collect(Collectors.toList())))
-            .collect(Collectors.toList());
+            .map(entry -> new PermittableGroup(entry.getKey(), entry.getValue().stream().collect(Collectors.toList())));
+  }
+
+  private static Stream<CallEndpointSet> getCallEndpointSets(
+          final @Nonnull List<ApplicationPermission> applicationPermissionRequirements) {
+
+    final Map<String, List<String>> permissionsGroupedByEndpointSet = applicationPermissionRequirements.stream()
+            .collect(Collectors.groupingBy(ApplicationPermission::getEndpointSetIdentifier,
+                    Collectors.mapping(x -> x.getPermission().getPermittableEndpointGroupIdentifier(), Collectors.toList())));
+
+    return permissionsGroupedByEndpointSet.entrySet().stream().map(entry -> {
+      final CallEndpointSet ret = new CallEndpointSet();
+      ret.setIdentifier(entry.getKey());
+      ret.setPermittableEndpointGroupIdentifiers(entry.getValue());
+      return ret;
+    });
   }
 
   void createOrFindPermittableGroup(
@@ -178,14 +223,14 @@
           final @Nonnull PermittableGroup permittableGroup) {
     try {
       identityService.createPermittableGroup(permittableGroup);
-      logger.info("Group '{}' successfully created in identity service.", permittableGroup.getIdentifier());
+      logger.info("Group '{}' successfully created in identity service for tenant {}.", permittableGroup.getIdentifier(), TenantContextHolder.checkedGetIdentifier());
     }
     catch (final PermittableGroupAlreadyExistsException groupAlreadyExistsException)
     {
       //if the group already exists, read out and compare.  If the group is the same, there is nothing left to do.
       final PermittableGroup existingGroup = identityService.getPermittableGroup(permittableGroup.getIdentifier());
       if (!existingGroup.getIdentifier().equals(permittableGroup.getIdentifier())) {
-        logger.error("Group '{}' already exists, but has a different name{} (strange).", permittableGroup.getIdentifier(), existingGroup.getIdentifier());
+        logger.error("Group '{}' already exists, but has a different name {} (strange).", permittableGroup.getIdentifier(), existingGroup.getIdentifier());
       }
 
       //Compare as sets because I'm not going to get into a hissy fit over order.
@@ -200,4 +245,63 @@
       logger.error("Creating group '{}' failed.", permittableGroup.getIdentifier(), unexpected);
     }
   }
+
+  private void createOrFindApplicationPermission(
+          final @Nonnull IdentityManager identityService,
+          final @Nonnull String applicationName,
+          final @Nonnull ApplicationPermission applicationPermission) {
+    try {
+      identityService.createApplicationPermission(applicationName, applicationPermission.getPermission());
+    }
+    catch (final ApplicationPermissionAlreadyExistsException alreadyExistsException)
+    {
+      //if exists, read out and compare.  If is the same, there is nothing left to do.
+      final Permission existing = identityService.getApplicationPermission(
+              applicationName, applicationPermission.getPermission().getPermittableEndpointGroupIdentifier());
+      if (!existing.getPermittableEndpointGroupIdentifier().equals(applicationPermission.getPermission().getPermittableEndpointGroupIdentifier())) {
+        logger.error("Application permission '{}' already exists, but has a different name {} (strange).",
+                applicationPermission.getPermission().getPermittableEndpointGroupIdentifier(), existing.getPermittableEndpointGroupIdentifier());
+      }
+
+      final Set<AllowedOperation> existingAllowedOperations = existing.getAllowedOperations();
+      final Set<AllowedOperation> newAllowedOperations = applicationPermission.getPermission().getAllowedOperations();
+      if (!existingAllowedOperations.equals(newAllowedOperations)) {
+        logger.error("Permission '{}' already exists, but has different contents.", applicationPermission.getPermission().getPermittableEndpointGroupIdentifier());
+      }
+    }
+    catch (final RuntimeException unexpected)
+    {
+      logger.error("Creating permission '{}' failed.", applicationPermission.getPermission().getPermittableEndpointGroupIdentifier(), unexpected);
+    }
+  }
+
+  private void createOrFindApplicationCallEndpointSet(
+          final @Nonnull IdentityManager identityService,
+          final @Nonnull String applicationName,
+          final @Nonnull CallEndpointSet callEndpointSet) {
+    try {
+      identityService.createApplicationCallEndpointSet(applicationName, callEndpointSet);
+    }
+    catch (final CallEndpointSetAlreadyExistsException alreadyExistsException)
+    {
+      //if already exists, read out and compare.  If is the same, there is nothing left to do.
+      final CallEndpointSet existing = identityService.getApplicationCallEndpointSet(
+              applicationName, callEndpointSet.getIdentifier());
+      if (!existing.getIdentifier().equals(callEndpointSet.getIdentifier())) {
+        logger.error("Application call endpoint set '{}' already exists, but has a different name {} (strange).",
+                callEndpointSet.getIdentifier(), existing.getIdentifier());
+      }
+
+      //Compare as sets because I'm not going to get into a hissy fit over order.
+      final Set<String> existingPermittableEndpoints = new HashSet<>(existing.getPermittableEndpointGroupIdentifiers());
+      final Set<String> newPermittableEndpoints = new HashSet<>(callEndpointSet.getPermittableEndpointGroupIdentifiers());
+      if (!existingPermittableEndpoints.equals(newPermittableEndpoints)) {
+        logger.error("Application call endpoint set '{}' already exists, but has different contents.", callEndpointSet.getIdentifier());
+      }
+    }
+    catch (final RuntimeException unexpected)
+    {
+      logger.error("Creating application call endpoint set '{}' failed.", callEndpointSet.getIdentifier(), unexpected);
+    }
+  }
 }
diff --git a/service/src/test/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializerTest.java b/service/src/test/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializerTest.java
index c32884c..ebe6e18 100644
--- a/service/src/test/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializerTest.java
+++ b/service/src/test/java/io/mifos/provisioner/internal/service/applications/IdentityServiceInitializerTest.java
@@ -28,6 +28,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.isA;
@@ -76,13 +77,13 @@
   public void getPermittableGroups() throws Exception {
 
     final List<PermittableEndpoint> permittableEndpoints = Arrays.asList(abcPost1, abcGet1, defGet1, abcPost2, abcGet2, defGet2, defGet3);
-    final List<PermittableGroup> ret = IdentityServiceInitializer.getPermittableGroups(permittableEndpoints);
+    final List<PermittableGroup> ret = IdentityServiceInitializer.getPermittableGroups(permittableEndpoints).collect(Collectors.toList());
     Assert.assertEquals(ret, Arrays.asList(group1, group2, group3));
   }
 
   @Test
   public void getPermittableGroupsOnEmptyList() throws Exception {
-    final List<PermittableGroup> ret = IdentityServiceInitializer.getPermittableGroups(Collections.emptyList());
+    final List<PermittableGroup> ret = IdentityServiceInitializer.getPermittableGroups(Collections.emptyList()).collect(Collectors.toList());
     Assert.assertEquals(ret, Collections.emptyList());
   }
 
diff --git a/shared.gradle b/shared.gradle
index 8a2c8dc..77669da 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -4,6 +4,7 @@
 ext.versions = [
         mifosidentityservice : '0.1.0-BUILD-SNAPSHOT',
         frameworkanubis      : '0.1.0-BUILD-SNAPSHOT',
+        frameworkanput       : '0.1.0-BUILD-SNAPSHOT',
         frameworkapi         : '0.1.0-BUILD-SNAPSHOT',
         frameworklang        : '0.1.0-BUILD-SNAPSHOT',
         frameworkasync       : '0.1.0-BUILD-SNAPSHOT',