Skip to content
Permalink
Browse files
Initializing application:
* signature
* permission requests
* call endpoint sets
for permitted-feign-client.
  • Loading branch information
mifosio-04-04-2018 committed May 3, 2017
1 parent 9b168db commit cc53c0d884a92939a5b361a9227b244dfb4b6609
Showing 3 changed files with 170 additions and 16 deletions.
@@ -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 @@ boolean isValidSecurityContext() {

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 @@ public ApplicationSignatureSet answer(final InvocationOnMock invocation) throws
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 @@ boolean isValidSecurityContext() {
}
}


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 @@ public void testTenantApplicationAssignment() throws InterruptedException {
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 @@ public void testTenantApplicationAssignment() throws InterruptedException {
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());
}
}
@@ -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 @@ public void postApplicationDetails(
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 @@ public void postApplicationDetails(
= 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 @@ List<PermittableEndpoint> getPermittables(final @Nonnull String applicationUri)
}
}

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 @@ void createOrFindPermittableGroup(
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);
}
}
}
@@ -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 getPermittablesAnubisCallFails() throws Exception {
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());
}

0 comments on commit cc53c0d

Please sign in to comment.