Merge pull request #13 from myrle-krantz/develop

Improved configuration validation
diff --git a/component-test/src/main/java/io/mifos/provisioner/AbstractServiceTest.java b/component-test/src/main/java/io/mifos/provisioner/AbstractServiceTest.java
index f47ca69..2aac655 100644
--- a/component-test/src/main/java/io/mifos/provisioner/AbstractServiceTest.java
+++ b/component-test/src/main/java/io/mifos/provisioner/AbstractServiceTest.java
@@ -17,7 +17,6 @@
 
 import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.provisioner.api.v1.client.Provisioner;
-import io.mifos.provisioner.config.ProvisionerActiveMQProperties;
 import io.mifos.provisioner.config.ProvisionerServiceConfig;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
@@ -37,11 +36,7 @@
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
-        classes = {AbstractServiceTest.TestConfiguration.class},
-        properties = {
-                ProvisionerActiveMQProperties.ACTIVEMQ_BROKER_URL_PROP + "=" + ProvisionerActiveMQProperties.ACTIVEMQ_BROKER_URL_DEFAULT,
-                ProvisionerActiveMQProperties.ACTIVEMQ_CONCURRENCY_PROP + "=" + ProvisionerActiveMQProperties.ACTIVEMQ_CONCURRENCY_DEFAULT}
-)
+        classes = {AbstractServiceTest.TestConfiguration.class})
 public class AbstractServiceTest {
   private static final String APP_NAME = "provisioner-v1";
   private static final String CLIENT_ID = "sillyRabbit";
@@ -72,6 +67,7 @@
           .around(mariaDBInitializer)
           .around(cassandraInitializer);
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
   protected Provisioner provisioner;
 
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 a72bb38..b0e6411 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
@@ -21,7 +21,6 @@
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.PermittableEndpoint;
 import io.mifos.anubis.api.v1.domain.Signature;
-import io.mifos.anubis.provider.SystemRsaKeyProvider;
 import io.mifos.anubis.test.v1.SystemSecurityEnvironment;
 import io.mifos.core.api.context.AutoSeshat;
 import io.mifos.core.api.util.ApiConstants;
@@ -40,7 +39,6 @@
 import io.mifos.provisioner.ProvisionerMariaDBInitializer;
 import io.mifos.provisioner.api.v1.client.Provisioner;
 import io.mifos.provisioner.api.v1.domain.*;
-import io.mifos.provisioner.config.ProvisionerActiveMQProperties;
 import io.mifos.provisioner.config.ProvisionerConstants;
 import io.mifos.provisioner.config.ProvisionerServiceConfig;
 import io.mifos.provisioner.internal.listener.IdentityListener;
@@ -77,11 +75,7 @@
  * @author Myrle Krantz
  */
 @RunWith(SpringJUnit4ClassRunner.class)
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
-        properties = {
-                ProvisionerActiveMQProperties.ACTIVEMQ_BROKER_URL_PROP + "=" + ProvisionerActiveMQProperties.ACTIVEMQ_BROKER_URL_DEFAULT,
-                ProvisionerActiveMQProperties.ACTIVEMQ_CONCURRENCY_PROP + "=" + ProvisionerActiveMQProperties.ACTIVEMQ_CONCURRENCY_DEFAULT}
-)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
 public class TestTenantApplicationAssignment {
   private static final String APP_NAME = "provisioner-v1";
   private static final String CLIENT_ID = "sillyRabbit";
@@ -128,24 +122,21 @@
           .around(mariaDBInitializer)
           .around(cassandraInitializer);
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
   private Provisioner provisioner;
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
-  @Qualifier("tokenProviderSpy")
-  protected TokenProvider tokenProviderSpy;
+  private ApplicationCallContextProvider applicationCallContextProviderSpy;
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
-  protected ApplicationCallContextProvider applicationCallContextProviderSpy;
+  private IdentityListener identityListener;
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
-  protected SystemRsaKeyProvider systemRsaKeyProvider;
-
-  @Autowired
-  protected IdentityListener identityListener;
-
-  @Autowired
-  protected Gson gson;
+  private Gson gson;
 
   private AutoSeshat autoSeshat;
 
diff --git a/component-test/src/main/resources/application.yaml b/component-test/src/main/resources/application.yaml
new file mode 100644
index 0000000..3685c6b
--- /dev/null
+++ b/component-test/src/main/resources/application.yaml
@@ -0,0 +1,26 @@
+#
+# Copyright 2017 The Mifos Initiative.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+system:
+  domain: mifos.io
+  dataStoreOption: ALL # possible values ALL, CASSANDRA, RDBMS
+  token:
+    ttl: 60
+
+
+activemq:
+  brokerUrl: vm://localhost?broker.persistent=false
+  concurrency: 3-10
\ No newline at end of file
diff --git a/service/build.gradle b/service/build.gradle
index 2bd249e..373a0df 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -47,6 +47,10 @@
             [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator],
             [group: 'io.mifos.tools', name: 'crypto', version: versions.frameworkcrypto],
     )
+
+    testCompile(
+            [group: 'io.mifos.core', name: 'test', version: versions.frameworktest],
+    )
 }
 
 publishToMavenLocal.dependsOn bootRepackage
diff --git a/service/src/main/java/io/mifos/provisioner/config/CheckKeysValid.java b/service/src/main/java/io/mifos/provisioner/config/CheckKeysValid.java
new file mode 100644
index 0000000..6228e08
--- /dev/null
+++ b/service/src/main/java/io/mifos/provisioner/config/CheckKeysValid.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.provisioner.config;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+/**
+ * @author Myrle Krantz
+ */
+public class CheckKeysValid implements ConstraintValidator<KeysValid, SystemProperties> {
+
+  @Override
+  public void initialize(KeysValid constraintAnnotation) {
+  }
+
+  @Override
+  public boolean isValid(final SystemProperties value, final ConstraintValidatorContext context) {
+    if (value.getPrivateKey().getModulus() == null || value.getPrivateKey().getExponent() == null ||
+        value.getPublicKey().getModulus() == null ||value.getPublicKey().getExponent() == null)
+      return false;
+
+    try {
+      final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+      final RSAPrivateKeySpec rsaPrivateKeySpec
+          = new RSAPrivateKeySpec(value.getPrivateKey().getModulus(), value.getPrivateKey().getExponent());
+      final PrivateKey privateKey = keyFactory.generatePrivate(rsaPrivateKeySpec);
+
+      final RSAPublicKeySpec rsaPublicKeySpec
+          = new RSAPublicKeySpec(value.getPublicKey().getModulus(), value.getPublicKey().getExponent());
+      final PublicKey publicKey = keyFactory.generatePublic(rsaPublicKeySpec);
+
+      final Signature signature = Signature.getInstance("NONEwithRSA");
+      signature.initSign(privateKey);
+      final byte[] signed = signature.sign();
+
+      signature.initVerify(publicKey);
+      return signature.verify(signed);
+    } catch (final NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException e) {
+      return false;
+    }
+  }
+}
diff --git a/service/src/main/java/io/mifos/provisioner/config/KeysValid.java b/service/src/main/java/io/mifos/provisioner/config/KeysValid.java
new file mode 100644
index 0000000..9a582e3
--- /dev/null
+++ b/service/src/main/java/io/mifos/provisioner/config/KeysValid.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.provisioner.config;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+    validatedBy = {CheckKeysValid.class}
+)
+public @interface KeysValid {
+  String message() default "Public and private keys must be valid and matching.";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+}
diff --git a/service/src/main/java/io/mifos/provisioner/config/ProvisionerProperties.java b/service/src/main/java/io/mifos/provisioner/config/ProvisionerProperties.java
new file mode 100644
index 0000000..c007e6b
--- /dev/null
+++ b/service/src/main/java/io/mifos/provisioner/config/ProvisionerProperties.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.provisioner.config;
+
+import io.mifos.provisioner.internal.util.DataStoreOption;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import javax.validation.Valid;
+
+/**
+ * @author Myrle Krantz
+ */
+@ConfigurationProperties(prefix = "provisioner")
+public class ProvisionerProperties {
+  @Valid
+  private DataStoreOption dataStoreOption = DataStoreOption.ALL;
+
+  public DataStoreOption getDataStoreOption() {
+    return dataStoreOption;
+  }
+
+  public void setDataStoreOption(DataStoreOption dataStoreOption) {
+    this.dataStoreOption = dataStoreOption;
+  }
+}
diff --git a/service/src/main/java/io/mifos/provisioner/config/ProvisionerServiceConfig.java b/service/src/main/java/io/mifos/provisioner/config/ProvisionerServiceConfig.java
index 05b849a..c07cc54 100644
--- a/service/src/main/java/io/mifos/provisioner/config/ProvisionerServiceConfig.java
+++ b/service/src/main/java/io/mifos/provisioner/config/ProvisionerServiceConfig.java
@@ -15,7 +15,6 @@
  */
 package io.mifos.provisioner.config;
 
-import io.mifos.anubis.config.AnubisConstants;
 import io.mifos.anubis.config.EnableAnubis;
 import io.mifos.anubis.token.SystemAccessTokenSerializer;
 import io.mifos.core.api.util.ApiFactory;
@@ -36,14 +35,11 @@
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
 import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
 import org.springframework.jms.config.JmsListenerContainerFactory;
 import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
-import java.math.BigInteger;
-
 @Configuration
 @EnableAutoConfiguration
 @ComponentScan({
@@ -60,7 +56,7 @@
 @EnableCassandra
 @EnableServiceException
 @EnableApplicationName
-@EnableConfigurationProperties({ProvisionerActiveMQProperties.class})
+@EnableConfigurationProperties({ProvisionerActiveMQProperties.class, ProvisionerProperties.class, SystemProperties.class})
 public class ProvisionerServiceConfig extends WebMvcConfigurerAdapter {
 
   public ProvisionerServiceConfig() {
@@ -73,15 +69,15 @@
   }
 
   @Bean(name = "tokenProvider")
-  public TokenProvider tokenProvider(final Environment environment,
+  public TokenProvider tokenProvider(final SystemProperties systemProperties,
                                      @SuppressWarnings("SpringJavaAutowiringInspection") final SystemAccessTokenSerializer tokenSerializer,
                                      @Qualifier(ProvisionerConstants.LOGGER_NAME) final Logger logger) {
-    final String timestamp = environment.getProperty(AnubisConstants.PUBLIC_KEY_TIMESTAMP_PROPERTY);
+    final String timestamp = systemProperties.getPublicKey().getTimestamp();
     logger.info("Provisioner key timestamp: " + timestamp);
 
     return new TokenProvider( timestamp,
-        new BigInteger(environment.getProperty("system.privateKey.modulus")),
-        new BigInteger(environment.getProperty("system.privateKey.exponent")), tokenSerializer);
+        systemProperties.getPrivateKey().getModulus(),
+        systemProperties.getPrivateKey().getExponent(), tokenSerializer);
   }
 
   @Bean
diff --git a/service/src/main/java/io/mifos/provisioner/config/SystemProperties.java b/service/src/main/java/io/mifos/provisioner/config/SystemProperties.java
new file mode 100644
index 0000000..9335127
--- /dev/null
+++ b/service/src/main/java/io/mifos/provisioner/config/SystemProperties.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.provisioner.config;
+
+import org.hibernate.validator.constraints.NotEmpty;
+import org.hibernate.validator.constraints.Range;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.math.BigInteger;
+
+/**
+ * @author Myrle Krantz
+ */
+@KeysValid
+@ConfigurationProperties(prefix = "system")
+public class SystemProperties {
+  @NotEmpty
+  private String domain = "mifos.io";
+
+  @Valid
+  private final Token token = new Token();
+
+  @Valid
+  private final PublicKey publicKey = new PublicKey();
+
+  @Valid
+  private final PrivateKey privateKey = new PrivateKey();
+
+  public static class Token {
+    @Range(min = 1)
+    private int ttl = 60;
+
+    public int getTtl() {
+      return ttl;
+    }
+
+    public void setTtl(int ttl) {
+      this.ttl = ttl;
+    }
+  }
+
+  public static class PublicKey {
+    @NotEmpty
+    private String timestamp;
+
+    @NotNull
+    private BigInteger modulus;
+
+    @NotNull
+    private BigInteger exponent;
+
+    public String getTimestamp() {
+      return timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+      this.timestamp = timestamp;
+    }
+
+    public BigInteger getModulus() {
+      return modulus;
+    }
+
+    public void setModulus(BigInteger modulus) {
+      this.modulus = modulus;
+    }
+
+    public BigInteger getExponent() {
+      return exponent;
+    }
+
+    public void setExponent(BigInteger exponent) {
+      this.exponent = exponent;
+    }
+  }
+
+  public static class PrivateKey {
+    @NotNull
+    private BigInteger modulus;
+
+    @NotNull
+    private BigInteger exponent;
+
+    public BigInteger getModulus() {
+      return modulus;
+    }
+
+    public void setModulus(BigInteger modulus) {
+      this.modulus = modulus;
+    }
+
+    public BigInteger getExponent() {
+      return exponent;
+    }
+
+    public void setExponent(BigInteger exponent) {
+      this.exponent = exponent;
+    }
+  }
+
+  public String getDomain() {
+    return domain;
+  }
+
+  public void setDomain(String domain) {
+    this.domain = domain;
+  }
+
+  public Token getToken() {
+    return token;
+  }
+
+  public PublicKey getPublicKey() {
+    return publicKey;
+  }
+
+  public PrivateKey getPrivateKey() {
+    return privateKey;
+  }
+}
diff --git a/service/src/main/java/io/mifos/provisioner/internal/service/AuthenticationService.java b/service/src/main/java/io/mifos/provisioner/internal/service/AuthenticationService.java
index 465380e..7aa175c 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/service/AuthenticationService.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/service/AuthenticationService.java
@@ -27,6 +27,7 @@
 import io.mifos.anubis.token.TokenSerializationResult;
 import io.mifos.core.cassandra.core.CassandraSessionProvider;
 import io.mifos.core.lang.ServiceException;
+import io.mifos.provisioner.config.SystemProperties;
 import io.mifos.provisioner.internal.repository.UserEntity;
 import io.mifos.provisioner.api.v1.domain.AuthenticationResponse;
 import io.mifos.provisioner.api.v1.domain.PasswordPolicy;
@@ -58,8 +59,7 @@
 
   @Value("${spring.application.name}")
   private String applicationName;
-  @Value("${system.token.ttl}")
-  private Integer ttl;
+  private final Integer ttl;
   private final Logger logger;
   private final CassandraSessionProvider cassandraSessionProvider;
   private final HashGenerator hashGenerator;
@@ -70,8 +70,10 @@
   public AuthenticationService(@Qualifier(ProvisionerConstants.LOGGER_NAME) final Logger logger,
                                final CassandraSessionProvider cassandraSessionProvider,
                                final HashGenerator hashGenerator,
-                               final TokenProvider tokenProvider) {
+                               final TokenProvider tokenProvider,
+                               final SystemProperties systemProperties) {
     super();
+    this.ttl = systemProperties.getToken().getTtl();
     this.logger = logger;
     this.cassandraSessionProvider = cassandraSessionProvider;
     this.hashGenerator = hashGenerator;
diff --git a/service/src/main/java/io/mifos/provisioner/internal/service/TenantService.java b/service/src/main/java/io/mifos/provisioner/internal/service/TenantService.java
index aa499a7..b648f39 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/service/TenantService.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/service/TenantService.java
@@ -23,6 +23,7 @@
 import io.mifos.provisioner.api.v1.domain.DatabaseConnectionInfo;
 import io.mifos.provisioner.api.v1.domain.Tenant;
 import io.mifos.provisioner.config.ProvisionerConstants;
+import io.mifos.provisioner.config.ProvisionerProperties;
 import io.mifos.provisioner.internal.repository.TenantCassandraRepository;
 import io.mifos.provisioner.internal.repository.TenantDAO;
 import io.mifos.provisioner.internal.repository.TenantEntity;
@@ -54,6 +55,7 @@
   private final TenantAuthorizationDataRepository tenantAuthorizationDataRepository;
   private final TenantCassandraRepository tenantCassandraRepository;
   private final IdentityServiceInitializer identityServiceInitializer;
+  private final ProvisionerProperties provisionerProperties;
 
 
   @Autowired
@@ -62,7 +64,8 @@
                        final TenantApplicationService tenantApplicationService,
                        @SuppressWarnings("SpringJavaAutowiringInspection") final TenantAuthorizationDataRepository tenantAuthorizationDataRepository,
                        final TenantCassandraRepository tenantCassandraRepository,
-                       final IdentityServiceInitializer identityServiceInitializer) {
+                       final IdentityServiceInitializer identityServiceInitializer,
+                       final ProvisionerProperties provisionerProperties) {
     super();
     this.logger = logger;
     this.environment = environment;
@@ -70,6 +73,7 @@
     this.tenantAuthorizationDataRepository = tenantAuthorizationDataRepository;
     this.tenantCassandraRepository = tenantCassandraRepository;
     this.identityServiceInitializer = identityServiceInitializer;
+    this.provisionerProperties = provisionerProperties;
   }
 
   public void create(final Tenant tenant) {
@@ -78,8 +82,7 @@
   }
 
   private void initializeKeyspace(final @Nonnull Tenant tenant) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-            this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.CASSANDRA)) {
       final CassandraConnectionInfo cassandraConnectionInfo = tenant.getCassandraConnectionInfo();
 
@@ -127,8 +130,7 @@
   }
 
   private void fetchAllCassandra(final @Nonnull List<Tenant> tenants) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-            this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.CASSANDRA)) {
       List<TenantEntity> tenantEntities = tenantCassandraRepository.fetchAll();
 
@@ -158,16 +160,13 @@
   }
 
   private void fetchAllDatabase(final ArrayList<Tenant> tenants) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.RDBMS)) {
       if (tenants.size() > 0) {
         try (final Connection connection = DataSourceUtils.createProvisionerConnection(this.environment)) {
           for (final Tenant tenant : tenants) {
             final Optional<TenantDAO> optionalTenantDAO = TenantDAO.find(connection, tenant.getIdentifier());
-            if (optionalTenantDAO.isPresent()) {
-              tenant.setDatabaseConnectionInfo(optionalTenantDAO.get().map());
-            }
+            optionalTenantDAO.ifPresent(tenantDAO -> tenant.setDatabaseConnectionInfo(tenantDAO.map()));
           }
         } catch (final SQLException sqlex) {
           this.logger.error(sqlex.getMessage(), sqlex);
@@ -191,8 +190,7 @@
   }
 
   private Optional<Tenant> findCassandra(final String identifier) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.CASSANDRA)) {
       return tenantCassandraRepository.get(identifier).map(x -> {
                 final Tenant tenant = new Tenant();
@@ -208,8 +206,7 @@
   }
 
   private Tenant findInDatabase(final @Nonnull Tenant tenant, final @Nonnull String identifier) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.RDBMS)) {
       try (final Connection connection = DataSourceUtils.createProvisionerConnection(this.environment)) {
         final Optional<TenantDAO> optionalTenantDAO = TenantDAO.find(connection, identifier);
@@ -226,8 +223,7 @@
   }
 
   private void initializeDatabase(final Tenant tenant) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.RDBMS)) {
 
       try (
@@ -274,8 +270,7 @@
   }
 
   private void deleteFromCassandra(final @Nonnull String identifier) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.CASSANDRA)) {
       final Optional<TenantEntity> tenantEntity = tenantCassandraRepository.get(identifier);
       tenantEntity.ifPresent(x ->
@@ -287,8 +282,7 @@
   }
 
   private void deleteDatabase(final String identifier) {
-    final DataStoreOption dataStoreOption = DataStoreOption.valueOf(
-        this.environment.getProperty(DataStoreOption.PROPERTY_NAME, DataStoreOption.PROPERTY_DEFAULT_VALUE));
+    final DataStoreOption dataStoreOption = provisionerProperties.getDataStoreOption();
     if (dataStoreOption.isEnabled(DataStoreOption.RDBMS)) {
 
       try (final Connection provisionerConnection = DataSourceUtils.createProvisionerConnection(this.environment)) {
@@ -321,4 +315,4 @@
     cassandraConnectionInfo.setReplicas(tenantEntity.getReplicas());
     return cassandraConnectionInfo;
   }
-}
+}
\ No newline at end of file
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 054cdf4..e955a82 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
@@ -33,13 +33,13 @@
 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.provisioner.config.SystemProperties;
 import io.mifos.provisioner.internal.listener.EventExpectation;
 import io.mifos.provisioner.internal.listener.IdentityListener;
 import io.mifos.tool.crypto.HashGenerator;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.util.Base64Utils;
 
@@ -58,9 +58,7 @@
   private final ApplicationCallContextProvider applicationCallContextProvider;
   private final HashGenerator hashGenerator;
   private final Logger logger;
-
-  @Value("${system.domain}")
-  private String domain;
+  private final SystemProperties systemProperties;
 
   public class IdentityServiceInitializationResult {
     private final ApplicationSignatureSet signatureSet;
@@ -83,14 +81,16 @@
 
   @Autowired
   public IdentityServiceInitializer(
-          final IdentityListener identityListener,
-          final ApplicationCallContextProvider applicationCallContextProvider,
-          final HashGenerator hashGenerator,
-          @Qualifier(ProvisionerConstants.LOGGER_NAME) final Logger logger) {
+      final IdentityListener identityListener,
+      final ApplicationCallContextProvider applicationCallContextProvider,
+      final HashGenerator hashGenerator,
+      @Qualifier(ProvisionerConstants.LOGGER_NAME) final Logger logger,
+      final SystemProperties systemProperties) {
     this.identityListener = identityListener;
     this.applicationCallContextProvider = applicationCallContextProvider;
     this.hashGenerator = hashGenerator;
     this.logger = logger;
+    this.systemProperties = systemProperties;
   }
 
   public IdentityServiceInitializationResult initializeIsis(
@@ -108,7 +108,7 @@
       final String nonRandomPassword = "ChangeThisPassword";
       this.logger.debug("Initial password for tenant super user '{}' is '{}'. This should be changed immediately.", tenantIdentifier, nonRandomPassword);
 
-      final byte[] salt = Base64Utils.encode(("antony" + tenantIdentifier + this.domain).getBytes());
+      final byte[] salt = Base64Utils.encode(("antony" + tenantIdentifier + this.systemProperties.getDomain()).getBytes());
 
       final String encodedPassword = Base64Utils.encodeToString(nonRandomPassword.getBytes());
 
diff --git a/service/src/main/java/io/mifos/provisioner/internal/util/DataStoreOption.java b/service/src/main/java/io/mifos/provisioner/internal/util/DataStoreOption.java
index e399e87..93be681 100644
--- a/service/src/main/java/io/mifos/provisioner/internal/util/DataStoreOption.java
+++ b/service/src/main/java/io/mifos/provisioner/internal/util/DataStoreOption.java
@@ -16,14 +16,10 @@
 package io.mifos.provisioner.internal.util;
 
 public enum DataStoreOption {
-
   ALL,
   CASSANDRA,
   RDBMS;
 
-  public static final String PROPERTY_NAME = "provisioner.dataStoreOption";
-  public static final String PROPERTY_DEFAULT_VALUE = "ALL";
-
   public boolean isEnabled(final DataStoreOption dataStoreOption) {
     return this == ALL || this == dataStoreOption;
   }
diff --git a/service/src/main/resources/application.yaml b/service/src/main/resources/application.yaml
index a81fb64..a7cb682 100644
--- a/service/src/main/resources/application.yaml
+++ b/service/src/main/resources/application.yaml
@@ -40,16 +40,4 @@
   host: localhost
   port: 3306
   user: root
-  password: mysql
-
-system:
-  domain: mifos.io
-  dataStoreOption: ALL # possible values ALL, CASSANDRA, RDBMS
-  token:
-    ttl: 60
-  publicKey:
-    modulus: 18127979232651385577366788312577367809882840493309321947218444859734692803519322053118166861938127116063250592470870009582066787630638146674578444578864162263848522570791848618846268461050665448704495233021189752693589550011013299642312910333176350540133789870795905610030842272086304844975800905158104573387446873659409802855678797448220593733004510515015951396676579423158731638742125820984712730134997911206145523653040544527593404472473700394782702820939632486955986794980759384390018112339579933792560176712866026367677322796321647134284719444328549297157384676116482642453484323266505460321391509718183529003027
-    exponent: 65537
-  privateKey:
-    modulus: 21809400075083175962379439196636583774179615274445790777150424827246273931119109792802133084303807180138431535925399383578649396318773218549617349819790628104138404726662789219140029410886208143215123139141187664102456961514206129348474466709463496369346914088323798703048475755436555987223468203468553348311906047130177940096755897503185024960411862964691833266166883793657798456516931118758087021056538684569379725109236404256856114833181540549166096374949146511824467497157749867316091008771844300966541141405006700507801915029195150283858166375276566250188795476921959861592976559593357049441618590308131364265579
-    exponent: 21396420147817994135788156653294258057961953456608733445346349614608945003207871633398018657985528578576690938460098551452963083231027402228759282909093462083764634791118157615298645513257238487818477460888075469599334311877525631209690927438724155249149780860015975119569171569823898008064453844549096023361509733785035971862734131323630295291168257391386295075723232870733702843606330265150935365874469583098879545352195378799348081884841607217548991402200557247623180340819881037965267728865652559122765679109621265487390005859372586004312679150166716877896425042632003598727801328367204703595952127984368962313153
+  password: mysql
\ No newline at end of file
diff --git a/service/src/test/java/io/mifos/provisioner/config/SystemPropertiesTest.java b/service/src/test/java/io/mifos/provisioner/config/SystemPropertiesTest.java
new file mode 100644
index 0000000..2850be5
--- /dev/null
+++ b/service/src/test/java/io/mifos/provisioner/config/SystemPropertiesTest.java
@@ -0,0 +1,54 @@
+package io.mifos.provisioner.config;
+
+import io.mifos.core.lang.security.RsaKeyPairFactory;
+import io.mifos.core.test.domain.ValidationTest;
+import io.mifos.core.test.domain.ValidationTestCase;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author Myrle Krantz
+ */
+public class SystemPropertiesTest extends ValidationTest<SystemProperties> {
+  private static final RsaKeyPairFactory.KeyPairHolder keyPairHolder = RsaKeyPairFactory.createKeyPair();
+
+  public SystemPropertiesTest(ValidationTestCase<SystemProperties> testCase) {
+    super(testCase);
+  }
+
+  @Override
+  protected SystemProperties createValidTestSubject() {
+    final SystemProperties ret = new SystemProperties();
+    ret.getPrivateKey().setModulus(keyPairHolder.getPrivateKeyMod());
+    ret.getPrivateKey().setExponent(keyPairHolder.getPrivateKeyExp());
+    ret.getPublicKey().setTimestamp(keyPairHolder.getTimestamp());
+    ret.getPublicKey().setModulus(keyPairHolder.getPublicKeyMod());
+    ret.getPublicKey().setExponent(keyPairHolder.getPublicKeyExp());
+    return ret;
+  }
+
+  @Parameterized.Parameters
+  public static Collection testCases() {
+    final Collection<ValidationTestCase> ret = new ArrayList<>();
+    ret.add(new ValidationTestCase<SystemProperties>("basicCase")
+        .adjustment(x -> {})
+        .valid(true));
+    ret.add(new ValidationTestCase<SystemProperties>("missing private modulus")
+        .adjustment(x -> x.getPrivateKey().setModulus(null))
+        .valid(false));
+    ret.add(new ValidationTestCase<SystemProperties>("mismatched keys")
+        .adjustment(x -> {
+          final RsaKeyPairFactory.KeyPairHolder keyPairHolder = RsaKeyPairFactory.createKeyPair();
+          x.getPrivateKey().setModulus(keyPairHolder.getPrivateKeyMod());
+          x.getPrivateKey().setExponent(keyPairHolder.getPrivateKeyExp());
+        })
+        .valid(false));
+    ret.add(new ValidationTestCase<SystemProperties>("missing timestamp")
+        .adjustment(x -> x.getPublicKey().setTimestamp(null))
+        .valid(false));
+    return ret;
+  }
+
+}
\ No newline at end of file
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 9644fbf..09cddf4 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
@@ -21,6 +21,7 @@
 import io.mifos.identity.api.v1.client.IdentityManager;
 import io.mifos.identity.api.v1.client.PermittableGroupAlreadyExistsException;
 import io.mifos.identity.api.v1.domain.PermittableGroup;
+import io.mifos.provisioner.config.SystemProperties;
 import io.mifos.provisioner.internal.listener.IdentityListener;
 import org.junit.Assert;
 import org.junit.Test;
@@ -67,7 +68,8 @@
     //noinspection unchecked
     when(anubisMock.getPermittableEndpoints()).thenThrow(IllegalStateException.class);
 
-    final List<PermittableEndpoint> ret = new IdentityServiceInitializer(identityListenerMock, applicationCallContextProviderMock, null, loggerMock)
+    final SystemProperties systemProperties = new SystemProperties();
+    final List<PermittableEndpoint> ret = new IdentityServiceInitializer(identityListenerMock, applicationCallContextProviderMock, null, loggerMock, systemProperties)
             .getPermittables("blah");
 
     Assert.assertEquals(ret, Collections.emptyList());
@@ -100,7 +102,8 @@
     doReturn(reorderedGroup1).when(identityServiceMock).getPermittableGroup(group1.getIdentifier());
 
     try (final AutoTenantContext ignored = new AutoTenantContext("blah")) {
-      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock).createOrFindPermittableGroup(identityServiceMock, group1);
+      final SystemProperties systemProperties = new SystemProperties();
+      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock, systemProperties).createOrFindPermittableGroup(identityServiceMock, group1);
     }
   }
 
@@ -114,7 +117,8 @@
     doReturn(changedGroup1).when(identityServiceMock).getPermittableGroup(group1.getIdentifier());
 
     try (final AutoTenantContext ignored = new AutoTenantContext("blah")) {
-      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock).createOrFindPermittableGroup(identityServiceMock, group1);
+      final SystemProperties systemProperties = new SystemProperties();
+      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock, systemProperties).createOrFindPermittableGroup(identityServiceMock, group1);
     }
 
     verify(loggerMock).error(anyString(), anyString(), anyString());
@@ -130,7 +134,8 @@
     doReturn(changedGroup1).when(identityServiceMock).getPermittableGroup(group1.getIdentifier());
 
     try (final AutoTenantContext ignored = new AutoTenantContext("blah")) {
-      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock).createOrFindPermittableGroup(identityServiceMock, group1);
+      final SystemProperties systemProperties = new SystemProperties();
+      new IdentityServiceInitializer(identityListenerMock, null, null, loggerMock, systemProperties).createOrFindPermittableGroup(identityServiceMock, group1);
     }
 
     verify(loggerMock).error(anyString(), anyString(), anyString(), isA(IllegalStateException.class));