Added synchronisation and extra error checking for if provisioner is called multiple times in rapid succession.
diff --git a/service/src/main/java/io/mifos/identity/internal/command/handler/Provisioner.java b/service/src/main/java/io/mifos/identity/internal/command/handler/Provisioner.java
index ecf1c61..304092e 100644
--- a/service/src/main/java/io/mifos/identity/internal/command/handler/Provisioner.java
+++ b/service/src/main/java/io/mifos/identity/internal/command/handler/Provisioner.java
@@ -96,7 +96,7 @@
this.saltGenerator = saltGenerator;
}
- public ApplicationSignatureSet provisionTenant(final String initialPasswordHash) {
+ public synchronized ApplicationSignatureSet provisionTenant(final String initialPasswordHash) {
logger.info("Provisioning cassandra tables for tenant {}...", TenantContextHolder.checkedGetIdentifier());
final RsaKeyPairFactory.KeyPairHolder keys = RsaKeyPairFactory.createKeyPair();
diff --git a/service/src/main/java/io/mifos/identity/internal/repository/Signatures.java b/service/src/main/java/io/mifos/identity/internal/repository/Signatures.java
index a54b003..040015d 100644
--- a/service/src/main/java/io/mifos/identity/internal/repository/Signatures.java
+++ b/service/src/main/java/io/mifos/identity/internal/repository/Signatures.java
@@ -39,6 +39,13 @@
import java.util.stream.StreamSupport;
/**
+ * All write accesses are synchronized. These occur only during provisioning or key rotation, so they are not
+ * performance critical. These are only necessary because for some reason (that I have not yet been able to track
+ * down), provisioning is being called multiple times in rapid succession for a tenant.
+ *
+ * All calls to cassandra which could conceivably be performed before provisioning is complete are surrounded by
+ * a try-catch block for an InvalidQueryException. If provisioning is not completed, the table is treated as empty.
+ *
* @author Myrle Krantz
*/
@Component
@@ -63,7 +70,7 @@
this.tenantAwareCassandraMapperProvider = tenantAwareCassandraMapperProvider;
}
- public void buildTable() {
+ public synchronized void buildTable() {
final Create create = SchemaBuilder.createTable(TABLE_NAME)
.ifNotExists()
.addPartitionKey(KEY_TIMESTAMP_COLUMN, DataType.text())
@@ -83,7 +90,7 @@
cassandraSessionProvider.getTenantSession().execute(createValidIndex);
}
- public SignatureEntity add(final RsaKeyPairFactory.KeyPairHolder keys)
+ public synchronized SignatureEntity add(final RsaKeyPairFactory.KeyPairHolder keys)
{
//There will only be one entry in this table.
final BoundStatement tenantCreationStatement =
@@ -116,11 +123,16 @@
}
public Optional<SignatureEntity> getSignature(final String keyTimestamp) {
- final Mapper<SignatureEntity> signatureEntityMapper
- = tenantAwareCassandraMapperProvider.getMapper(SignatureEntity.class);
+ try {
+ final Mapper<SignatureEntity> signatureEntityMapper
+ = tenantAwareCassandraMapperProvider.getMapper(SignatureEntity.class);
- final Optional<SignatureEntity> ret = Optional.ofNullable(signatureEntityMapper.get(keyTimestamp));
- return ret.filter(SignatureEntity::getValid);
+ final Optional<SignatureEntity> ret = Optional.ofNullable(signatureEntityMapper.get(keyTimestamp));
+ return ret.filter(SignatureEntity::getValid);
+ }
+ catch (final InvalidQueryException e) {
+ return Optional.empty();
+ }
}
/**
@@ -128,25 +140,24 @@
*/
public Optional<PrivateSignatureEntity> getPrivateSignature()
{
- try {
- final Optional<String> maximumKeyTimestamp = streamValidKeyTimestamps().max(String::compareTo);
+ final Optional<String> maximumKeyTimestamp = streamValidKeyTimestamps().max(String::compareTo);
- return maximumKeyTimestamp.flatMap(this::getPrivateSignatureEntity);
+ return maximumKeyTimestamp.flatMap(this::getPrivateSignatureEntity);
+ }
+
+ private Optional<PrivateSignatureEntity> getPrivateSignatureEntity(final String keyTimestamp) {
+ try {
+ final Mapper<PrivateSignatureEntity> privateSignatureEntityMapper
+ = tenantAwareCassandraMapperProvider.getMapper(PrivateSignatureEntity.class);
+
+ final Optional<PrivateSignatureEntity> ret = Optional.ofNullable(privateSignatureEntityMapper.get(keyTimestamp));
+ return ret.filter(PrivateSignatureEntity::getValid);
}
catch (final InvalidQueryException e) {
return Optional.empty();
}
}
- private Optional<PrivateSignatureEntity> getPrivateSignatureEntity(final String keyTimestamp) {
-
- final Mapper<PrivateSignatureEntity> privateSignatureEntityMapper
- = tenantAwareCassandraMapperProvider.getMapper(PrivateSignatureEntity.class);
-
- final Optional<PrivateSignatureEntity> ret = Optional.ofNullable(privateSignatureEntityMapper.get(keyTimestamp));
- return ret.filter(PrivateSignatureEntity::getValid);
- }
-
public List<String> getAllKeyTimestamps() {
return streamValidKeyTimestamps().collect(Collectors.toList());
}
@@ -165,9 +176,8 @@
}
}
- public void invalidateEntry(final String keyTimestamp) {
+ public synchronized void invalidateEntry(final String keyTimestamp) {
final Update.Assignments updateQuery = QueryBuilder.update(TABLE_NAME).where(QueryBuilder.eq(KEY_TIMESTAMP_COLUMN, keyTimestamp)).with(QueryBuilder.set(VALID_COLUMN, false));
cassandraSessionProvider.getTenantSession().execute(updateQuery);
-
}
}