Initializing application:
* signature
* permission requests
* call endpoint sets
for permitted-feign-client.
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 1997a73..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;
@@ -235,11 +240,13 @@
 
   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, final String tenantIdentifier) {
+    private VerifyCreateSignatureSetContext(final RsaKeyPairFactory.KeyPairHolder answer, final String target, final String tenantIdentifier) {
+      this.answer = answer;
       this.target = target;
       this.tenantIdentifier = tenantIdentifier;
     }
@@ -249,10 +256,10 @@
       final String timestamp = invocation.getArgumentAt(0, String.class);
       final Signature identityManagerSignature = invocation.getArgumentAt(1, Signature.class);
       validSecurityContext = systemSecurityEnvironment.isValidSystemSecurityContext(target, "1", tenantIdentifier);
-      final RsaKeyPairFactory.KeyPairHolder keys = RsaKeyPairFactory.createKeyPair();
+
       return new ApplicationSignatureSet(
               timestamp,
-              new Signature(keys.getPublicKeyMod(), keys.getPublicKeyExp()),
+              new Signature(answer.getPublicKeyMod(), answer.getPublicKeyExp()),
               identityManagerSignature);
     }
 
@@ -284,6 +291,29 @@
     }
   }
 
+
+  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;
+    }
+
+    boolean isValidSecurityContext() {
+      return validSecurityContext;
+    }
+  }
+
   @Test
   public void testTenantApplicationAssignment() throws InterruptedException {
     //Create io.mifos.provisioner.tenant
@@ -350,23 +380,34 @@
     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;
+    final VerifyAnputRequiredPermissionsContext verifyAnputRequiredPermissionsContext;
     try (final AutoTenantContext ignored = new AutoTenantContext(tenant.getIdentifier())) {
       verifyAnubisInitializeContext = new VerifyAnubisInitializeContext("office", tenant.getIdentifier());
-      verifyCreateSignatureSetContext = new VerifyCreateSignatureSetContext("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));
@@ -377,11 +418,22 @@
     verify(applicationCallContextProviderSpy, never()).getApplicationCallContext(eq(Fixture.TENANT_NAME), Mockito.anyString());
     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/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 c92297e..9d45d18 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,17 @@
 
 
 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.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 +41,7 @@
 import javax.annotation.Nonnull;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author Myrle Krantz
@@ -132,8 +136,11 @@
           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);
     }
@@ -142,10 +149,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);
     }
@@ -164,15 +177,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(
@@ -202,4 +244,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());
   }