Skip to content
Permalink
Browse files
Making it possible to call initialize multiple times.
  • Loading branch information
myrle-krantz committed Jul 12, 2017
1 parent ee9bab3 commit 7891ae8c80cc8742e18cbae6011f34aba62c4bf1
Showing 7 changed files with 49 additions and 80 deletions.
@@ -226,7 +226,6 @@ boolean getApplicationPermissionEnabledForUser(@PathVariable("applicationidentif
@RequestMapping(value = "/initialize", method = RequestMethod.POST,
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE})
@ThrowsException(status = HttpStatus.CONFLICT, exception = TenantAlreadyInitializedException.class)
ApplicationSignatureSet initialize(@RequestParam("password") String password);

@RequestMapping(value = "/signatures", method = RequestMethod.POST,

This file was deleted.

@@ -83,7 +83,6 @@ public TestConfiguration() {
final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
private final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer);
private static boolean alreadyInitialized = false;

@ClassRule
public static TestRule orderClassRules = RuleChain
@@ -108,12 +107,9 @@ public TestConfiguration() {
public void provision() throws Exception {
identityManager = apiFactory.create(IdentityManager.class, testEnvironment.serverURI());

if (!alreadyInitialized) {
try (final AutoUserContext ignored
= tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
identityManager.initialize(TestEnvironment.encodePassword(ADMIN_PASSWORD));
}
alreadyInitialized = true;
try (final AutoUserContext ignored
= tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
identityManager.initialize(TestEnvironment.encodePassword(ADMIN_PASSWORD));
}
}

@@ -25,7 +25,6 @@
import io.mifos.core.lang.TenantContextHolder;
import io.mifos.core.test.env.TestEnvironment;
import io.mifos.identity.api.v1.client.IdentityManager;
import io.mifos.identity.api.v1.client.TenantAlreadyInitializedException;
import org.junit.Assert;
import org.junit.Test;

@@ -94,23 +93,16 @@ public void testBoundaryInitializeCases() throws InterruptedException {
Assert.assertTrue("The exception should be 'not found'", (e instanceof InvalidTokenException));
}

// The second otherwise valid call to initialize for the same tenant should
// not fail even though the tenant is now already initialized.
try (final AutoUserContext ignored2 = tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
firstTenantSignatureSet = testSubject.initialize(TestEnvironment.encodePassword(ADMIN_PASSWORD));

final Signature applicationSignature = tenantApplicationSecurityEnvironment.getAnubis().getApplicationSignature(firstTenantSignatureSet.getTimestamp());
firstTenantIdentityManagerSignature = tenantApplicationSecurityEnvironment.getAnubis().getSignatureSet(firstTenantSignatureSet.getTimestamp()).getIdentityManagerSignature();
Assert.assertEquals(applicationSignature, firstTenantIdentityManagerSignature);
}


try (final AutoUserContext ignored2 = tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
testSubject.initialize("golden_osiris");
Assert.fail("The second otherwise valid call to initialize for the same tenant should "
+ "fail because the tenant is now already initialized.");
}
catch (final TenantAlreadyInitializedException e)
{
//All is well.
}
}

@@ -18,6 +18,7 @@
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Update;
@@ -32,6 +33,7 @@
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
@@ -126,14 +128,14 @@ public Optional<SignatureEntity> getSignature(final String keyTimestamp) {
*/
public Optional<PrivateSignatureEntity> getPrivateSignature()
{
final Select.Where query = QueryBuilder.select(KEY_TIMESTAMP_COLUMN).from(TABLE_NAME).where(QueryBuilder.eq(VALID_COLUMN, Boolean.TRUE));
final ResultSet result = cassandraSessionProvider.getTenantSession().execute(query);
final Optional<String> maximumKeyTimestamp =
StreamSupport.stream(result.spliterator(), false)
.map(x -> x.get(KEY_TIMESTAMP_COLUMN, String.class))
.max(String::compareTo);

return maximumKeyTimestamp.flatMap(this::getPrivateSignatureEntity);
try {
final Optional<String> maximumKeyTimestamp = streamValidKeyTimestamps().max(String::compareTo);

return maximumKeyTimestamp.flatMap(this::getPrivateSignatureEntity);
}
catch (final InvalidQueryException e) {
return Optional.empty();
}
}

private Optional<PrivateSignatureEntity> getPrivateSignatureEntity(final String keyTimestamp) {
@@ -146,11 +148,21 @@ private Optional<PrivateSignatureEntity> getPrivateSignatureEntity(final String
}

public List<String> getAllKeyTimestamps() {
final Select.Where selectValid = QueryBuilder.select(KEY_TIMESTAMP_COLUMN).from(TABLE_NAME).where(QueryBuilder.eq(VALID_COLUMN, true));
final ResultSet result = cassandraSessionProvider.getTenantSession().execute(selectValid);
return StreamSupport.stream(result.spliterator(), false)
.map(x -> x.get(KEY_TIMESTAMP_COLUMN, String.class))
.collect(Collectors.toList());
return streamValidKeyTimestamps().collect(Collectors.toList());
}

private Stream<String> streamValidKeyTimestamps() {
try {
final Select.Where selectValid = QueryBuilder.select(KEY_TIMESTAMP_COLUMN)
.from(TABLE_NAME)
.where(QueryBuilder.eq(VALID_COLUMN, true));
final ResultSet result = cassandraSessionProvider.getTenantSession().execute(selectValid);
return StreamSupport.stream(result.spliterator(), false)
.map(x -> x.get(KEY_TIMESTAMP_COLUMN, String.class));
}
catch (final InvalidQueryException e) {
return Stream.empty();
}
}

public void invalidateEntry(final String keyTimestamp) {
@@ -15,7 +15,6 @@
*/
package io.mifos.identity.internal.service;

import com.datastax.driver.core.exceptions.InvalidQueryException;
import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
import io.mifos.anubis.api.v1.domain.Signature;
import io.mifos.anubis.config.TenantSignatureRepository;
@@ -25,7 +24,6 @@
import io.mifos.identity.internal.repository.PrivateSignatureEntity;
import io.mifos.identity.internal.repository.SignatureEntity;
import io.mifos.identity.internal.repository.Signatures;
import io.mifos.identity.internal.repository.Tenants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@@ -39,13 +37,11 @@
*/
@Service
public class TenantService implements TenantSignatureRepository {
private final Tenants tenants;
private final Signatures signatures;

@Autowired
TenantService(final Tenants tenants, final Signatures signatures)
TenantService(final Signatures signatures)
{
this.tenants = tenants;
this.signatures = signatures;
}

@@ -76,16 +72,6 @@ public Optional<Signature> getApplicationSignature(final String keyTimestamp) {
return signatureEntity.map(x -> new Signature(x.getPublicKeyMod(), x.getPublicKeyExp()));
}

public boolean tenantAlreadyProvisioned() {
try {
return tenants.currentTenantAlreadyProvisioned();
}
catch (final InvalidQueryException e)
{
return false;
}
}

public ApplicationSignatureSet createSignatureSet() {
final RsaKeyPairFactory.KeyPairHolder keys = RsaKeyPairFactory.createKeyPair();
final SignatureEntity signatureEntity = signatures.add(keys);
@@ -18,14 +18,19 @@
import io.mifos.anubis.annotation.AcceptedTokenType;
import io.mifos.anubis.annotation.Permittable;
import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
import io.mifos.core.command.gateway.CommandGateway;
import io.mifos.identity.internal.command.ChangeUserPasswordCommand;
import io.mifos.identity.internal.command.handler.Provisioner;
import io.mifos.identity.internal.service.TenantService;
import io.mifos.identity.internal.util.IdentityConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

/**
* @author Myrle Krantz
*/
@@ -35,14 +40,17 @@
public class InitializeRestController {
private final TenantService tenantService;
private final Provisioner provisioner;
private final CommandGateway commandGateway;

@Autowired
InitializeRestController(
final TenantService tenantService,
final Provisioner provisioner)
final Provisioner provisioner,
final CommandGateway commandGateway)
{
this.tenantService = tenantService;
this.provisioner = provisioner;
this.commandGateway = commandGateway;
}

@RequestMapping(value = "/initialize",
@@ -53,16 +61,15 @@ public class InitializeRestController {
public @ResponseBody ResponseEntity<ApplicationSignatureSet> initializeTenant(
@RequestParam("password") final String adminPassword)
{
if (tenantService.tenantAlreadyProvisioned())
{
return new ResponseEntity<>(HttpStatus.CONFLICT);
}


final ApplicationSignatureSet signatureSet = provisioner.provisionTenant(adminPassword);

return new ResponseEntity<>(signatureSet,
HttpStatus.OK);
return tenantService.getLatestSignatureSet()
.map(existingSignatureSet -> {
this.commandGateway.process(new ChangeUserPasswordCommand(IdentityConstants.SU_NAME, adminPassword));
return new ResponseEntity<>(existingSignatureSet, HttpStatus.OK);
})
.orElseGet(() -> {
final ApplicationSignatureSet newSignatureSet = provisioner.provisionTenant(adminPassword);
return new ResponseEntity<>(newSignatureSet, HttpStatus.OK);
});
}

@RequestMapping(value = "/signatures",

0 comments on commit 7891ae8

Please sign in to comment.