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());
}