Added test for key rotation, and fixed the bugs it turned up.
diff --git a/api/src/main/java/io/mifos/anubis/api/v1/client/Anubis.java b/api/src/main/java/io/mifos/anubis/api/v1/client/Anubis.java
index 05284aa..6f7ce43 100644
--- a/api/src/main/java/io/mifos/anubis/api/v1/client/Anubis.java
+++ b/api/src/main/java/io/mifos/anubis/api/v1/client/Anubis.java
@@ -19,10 +19,12 @@
 import io.mifos.anubis.api.v1.domain.PermittableEndpoint;
 import io.mifos.anubis.api.v1.domain.Signature;
 import io.mifos.anubis.api.v1.validation.ValidKeyTimestamp;
-import io.mifos.core.api.util.InvalidTokenException;
 import org.springframework.cloud.netflix.feign.FeignClient;
 import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 
 import java.util.List;
 
@@ -37,33 +39,34 @@
   )
   List<PermittableEndpoint> getPermittableEndpoints();
 
+  @RequestMapping(value = "/signatures", method = RequestMethod.GET,
+          consumes = {MediaType.APPLICATION_JSON_VALUE},
+          produces = {MediaType.ALL_VALUE})
+  List<String> getAllSignatureSets();
+
   @RequestMapping(value = "/signatures/{timestamp}", method = RequestMethod.POST,
           consumes = {MediaType.APPLICATION_JSON_VALUE},
           produces = {MediaType.ALL_VALUE})
   ApplicationSignatureSet createSignatureSet(@PathVariable("timestamp") @ValidKeyTimestamp String timestamp,
-                                             @RequestBody Signature identityManagerSignature)
-          throws InvalidTokenException, TenantNotFoundException;
+                                             @RequestBody Signature identityManagerSignature);
 
   @RequestMapping(value = "/signatures/{timestamp}", method = RequestMethod.GET,
           consumes = {MediaType.APPLICATION_JSON_VALUE},
           produces = {MediaType.ALL_VALUE})
-  ApplicationSignatureSet getSignatureSet(@PathVariable("timestamp") String timestamp)
-          throws InvalidTokenException, TenantNotFoundException;
+  ApplicationSignatureSet getSignatureSet(@PathVariable("timestamp") String timestamp);
 
   @RequestMapping(value = "/signatures/{timestamp}", method = RequestMethod.DELETE,
           consumes = {MediaType.APPLICATION_JSON_VALUE},
           produces = {MediaType.ALL_VALUE})
-  void deleteSignatureSet(@PathVariable("timestamp") String timestamp)
-          throws InvalidTokenException, TenantNotFoundException;
+  void deleteSignatureSet(@PathVariable("timestamp") String timestamp);
 
   @RequestMapping(value = "/signatures/{timestamp}/application", method = RequestMethod.GET,
           consumes = {MediaType.APPLICATION_JSON_VALUE},
           produces = {MediaType.ALL_VALUE})
-  Signature getApplicationSignature(@PathVariable("timestamp") String timestamp)
-          throws InvalidTokenException, TenantNotFoundException;
+  Signature getApplicationSignature(@PathVariable("timestamp") String timestamp);
 
   @RequestMapping(value = "/initialize", method = RequestMethod.POST,
           consumes = {MediaType.APPLICATION_JSON_VALUE},
           produces = {MediaType.ALL_VALUE})
-  void initializeResources() throws InvalidTokenException, TenantNotFoundException;
+  void initializeResources();
 }
diff --git a/api/src/main/java/io/mifos/anubis/api/v1/client/AnubisApiFactory.java b/api/src/main/java/io/mifos/anubis/api/v1/client/AnubisApiFactory.java
index 623c74b..799109e 100644
--- a/api/src/main/java/io/mifos/anubis/api/v1/client/AnubisApiFactory.java
+++ b/api/src/main/java/io/mifos/anubis/api/v1/client/AnubisApiFactory.java
@@ -18,21 +18,23 @@
 import feign.Feign;
 import feign.gson.GsonDecoder;
 import feign.gson.GsonEncoder;
+import io.mifos.core.api.util.AnnotatedErrorDecoder;
 import io.mifos.core.api.util.TenantedTargetInterceptor;
 import io.mifos.core.api.util.TokenedTargetInterceptor;
+import org.slf4j.Logger;
 import org.springframework.cloud.netflix.feign.support.SpringMvcContract;
 
 @SuppressWarnings("unused")
 public interface AnubisApiFactory {
 
-  static Anubis create(final String target) {
+  static Anubis create(final String target, final Logger logger) {
     return Feign.builder()
-        .contract(new SpringMvcContract())
-        .errorDecoder(new InitializeErrorDecoder())
-        .requestInterceptor(new TenantedTargetInterceptor())
-        .requestInterceptor(new TokenedTargetInterceptor())
-        .decoder(new GsonDecoder())
-        .encoder(new GsonEncoder())
-        .target(Anubis.class, target);
+            .contract(new SpringMvcContract())
+            .errorDecoder(new AnnotatedErrorDecoder(logger, Anubis.class))
+            .requestInterceptor(new TenantedTargetInterceptor())
+            .requestInterceptor(new TokenedTargetInterceptor())
+            .decoder(new GsonDecoder())
+            .encoder(new GsonEncoder())
+            .target(Anubis.class, target);
   }
 }
diff --git a/api/src/main/java/io/mifos/anubis/api/v1/client/InitializeErrorDecoder.java b/api/src/main/java/io/mifos/anubis/api/v1/client/InitializeErrorDecoder.java
deleted file mode 100644
index c1a0dab..0000000
--- a/api/src/main/java/io/mifos/anubis/api/v1/client/InitializeErrorDecoder.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.anubis.api.v1.client;
-
-import feign.Feign;
-import feign.FeignException;
-import feign.Response;
-import feign.codec.ErrorDecoder;
-import io.mifos.anubis.api.v1.domain.Signature;
-import io.mifos.core.api.util.InvalidTokenException;
-import org.apache.http.HttpStatus;
-
-import java.lang.reflect.Method;
-
-/**
- * @author Myrle Krantz
- */
-class InitializeErrorDecoder implements ErrorDecoder {
-  @Override public Exception decode(final String methodKey, final Response response) {
-    try {
-      final Method createSignatureSetMethod = Anubis.class.getDeclaredMethod("createSignatureSet", String.class, Signature.class);
-      final String createSignatureSetMethodKey =  Feign.configKey(Anubis.class, createSignatureSetMethod);
-      final Method initializeResourcesMethod = Anubis.class.getDeclaredMethod("initializeResources");
-      final String initializeResourcesMethodKey =  Feign.configKey(Anubis.class, initializeResourcesMethod);
-      if (createSignatureSetMethodKey.equals(methodKey) || initializeResourcesMethodKey.equals(methodKey))
-      {
-        if (response.status() == HttpStatus.SC_BAD_REQUEST)
-          return new IllegalArgumentException();
-        else if (response.status() == HttpStatus.SC_NOT_FOUND)
-          return new TenantNotFoundException();
-        else if (response.status() == HttpStatus.SC_FORBIDDEN)
-          return new InvalidTokenException(response.reason());
-      }
-
-      return FeignException.errorStatus(methodKey, response);
-    }
-    catch (final NoSuchMethodException e) {
-      throw new IllegalStateException("Could not find createSignatureSet method."); //TODO:
-    }
-  }
-}
diff --git a/api/src/main/java/io/mifos/anubis/api/v1/client/TenantNotFoundException.java b/api/src/main/java/io/mifos/anubis/api/v1/client/TenantNotFoundException.java
deleted file mode 100644
index 5f0b5c4..0000000
--- a/api/src/main/java/io/mifos/anubis/api/v1/client/TenantNotFoundException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.anubis.api.v1.client;
-
-/**
- * @author Myrle Krantz
- */
-@SuppressWarnings("WeakerAccess")
-public class TenantNotFoundException extends RuntimeException {
-}
diff --git a/component-test/src/main/java/TestAnubisInitialize.java b/component-test/src/main/java/TestAnubisInitialize.java
index d97fc0b..9d6343d 100644
--- a/component-test/src/main/java/TestAnubisInitialize.java
+++ b/component-test/src/main/java/TestAnubisInitialize.java
@@ -16,7 +16,6 @@
 
 import io.mifos.anubis.api.v1.client.Anubis;
 import io.mifos.anubis.api.v1.client.AnubisApiFactory;
-import io.mifos.anubis.api.v1.client.TenantNotFoundException;
 import io.mifos.anubis.api.v1.domain.Signature;
 import io.mifos.anubis.example.simple.Example;
 import io.mifos.anubis.example.simple.ExampleConfiguration;
@@ -24,6 +23,7 @@
 import io.mifos.core.api.context.AutoSeshat;
 import io.mifos.core.api.context.AutoUserContext;
 import io.mifos.core.api.util.InvalidTokenException;
+import io.mifos.core.api.util.NotFoundException;
 import io.mifos.core.lang.AutoTenantContext;
 import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.core.test.fixture.TenantDataStoreTestContext;
@@ -35,6 +35,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.cloud.netflix.feign.EnableFeignClients;
 import org.springframework.cloud.netflix.ribbon.RibbonClient;
@@ -52,6 +53,7 @@
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
 public class TestAnubisInitialize {
   private static final String APP_NAME = "anubis-v1";
+  private static final String LOGGER_QUALIFIER = "test-logger";
 
   @Configuration
   @EnableFeignClients(basePackages = {"io.mifos.anubis.example.simple"})
@@ -62,7 +64,7 @@
       super();
     }
 
-    @Bean()
+    @Bean(name = LOGGER_QUALIFIER)
     public Logger logger() {
       return LoggerFactory.getLogger(APP_NAME + "-logger");
     }
@@ -78,6 +80,11 @@
   @Autowired
   Example example;
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
+  @Autowired
+  @Qualifier(value = LOGGER_QUALIFIER)
+  Logger logger;
+
   @Test
   public void testBrokenToken()
   {
@@ -88,7 +95,7 @@
 
       try {
 
-        final Anubis anubis = AnubisApiFactory.create(testEnvironment.serverURI());
+        final Anubis anubis = AnubisApiFactory.create(testEnvironment.serverURI(), logger);
 
         try (final AutoSeshat ignored2 = new AutoSeshat(brokenSeshatToken)) {
           final TenantApplicationSecurityEnvironmentTestRule securityMock = new TenantApplicationSecurityEnvironmentTestRule(testEnvironment);
@@ -144,7 +151,7 @@
     }
   }
 
-  @Test(expected = TenantNotFoundException.class)
+  @Test(expected = NotFoundException.class)
   public void testNonExistentTenant() {
     try (final AutoTenantContext ignored = new AutoTenantContext("monster_under_your_bed")) {
       initialize();
diff --git a/component-test/src/main/java/TestAnubisInitializeWithSpecialTenantSignatureRepository.java b/component-test/src/main/java/TestAnubisInitializeWithSpecialTenantSignatureRepository.java
new file mode 100644
index 0000000..b9b973a
--- /dev/null
+++ b/component-test/src/main/java/TestAnubisInitializeWithSpecialTenantSignatureRepository.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+import io.mifos.anubis.example.nokeystorage.Example;
+import io.mifos.anubis.example.nokeystorage.ExampleConfiguration;
+import io.mifos.anubis.test.v1.SystemSecurityEnvironment;
+import io.mifos.core.api.context.AutoSeshat;
+import io.mifos.core.lang.AutoTenantContext;
+import io.mifos.core.lang.TenantContextHolder;
+import io.mifos.core.test.env.TestEnvironment;
+import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
+import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+import org.springframework.cloud.netflix.ribbon.RibbonClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author Myrle Krantz
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+public class TestAnubisInitializeWithSpecialTenantSignatureRepository {
+  private static final String APP_NAME = "anubis-v1";
+
+  @Configuration
+  @EnableFeignClients(basePackages = {"io.mifos.anubis.example.nokeystorage"})
+  @RibbonClient(name = APP_NAME)
+  @Import({ExampleConfiguration.class})
+  static public class TestConfiguration {
+    public TestConfiguration() {
+      super();
+    }
+
+    @Bean()
+    public Logger logger() {
+      return LoggerFactory.getLogger("initialize-with-special-tenant-signature-repository-test-logger");
+    }
+  }
+
+  @ClassRule
+  public final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
+
+  @ClassRule
+  public final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
+
+  @Rule
+  public final TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer);
+
+  @SuppressWarnings({"SpringAutowiredFieldsWarningInspection", "SpringJavaAutowiredMembersInspection"})
+  @Autowired
+  protected Example example;
+
+  @Test
+  public void test()
+  {
+    final SystemSecurityEnvironment systemSecurityEnvironment = new SystemSecurityEnvironment(
+            testEnvironment.getSystemKeyTimestamp(),
+            testEnvironment.getSystemPublicKey(),
+            testEnvironment.getSystemPrivateKey());
+
+    final String systemToken = systemSecurityEnvironment.systemToken(APP_NAME);
+
+    try (final AutoTenantContext ignored = new AutoTenantContext(TenantContextHolder.checkedGetIdentifier())) {
+      try (final AutoSeshat ignored2 = new AutoSeshat(systemToken)) {
+        example.initialize();
+      }}
+  }
+}
diff --git a/component-test/src/main/java/TestAnubisKeyRotation.java b/component-test/src/main/java/TestAnubisKeyRotation.java
new file mode 100644
index 0000000..9348fa0
--- /dev/null
+++ b/component-test/src/main/java/TestAnubisKeyRotation.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+import io.mifos.anubis.api.v1.client.Anubis;
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
+import io.mifos.anubis.api.v1.domain.Signature;
+import io.mifos.anubis.example.simple.Example;
+import io.mifos.anubis.example.simple.ExampleConfiguration;
+import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
+import io.mifos.core.api.context.AutoSeshat;
+import io.mifos.core.api.util.NotFoundException;
+import io.mifos.core.lang.security.RsaKeyPairFactory;
+import io.mifos.core.test.env.TestEnvironment;
+import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
+import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+import org.springframework.cloud.netflix.ribbon.RibbonClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+public class TestAnubisKeyRotation {
+  private static final String APP_NAME = "anubis-v1";
+
+  @Configuration
+  @EnableFeignClients(basePackages = {"io.mifos.anubis.example.simple"})
+  @RibbonClient(name = APP_NAME)
+  @Import({ExampleConfiguration.class})
+  static public class TestConfiguration {
+    public TestConfiguration() {
+      super();
+    }
+
+    @Bean()
+    public Logger logger() {
+      return LoggerFactory.getLogger("key-rotation-test-logger");
+    }
+  }
+
+  private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
+  private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
+  private final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer);
+
+  @ClassRule
+  public static TestRule orderClassRules = RuleChain
+          .outerRule(testEnvironment)
+          .around(cassandraInitializer)
+          .around(tenantDataStoreContext);
+
+  @Rule
+  public final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment
+          = new TenantApplicationSecurityEnvironmentTestRule(testEnvironment);
+
+  @SuppressWarnings({"SpringAutowiredFieldsWarningInspection", "SpringJavaAutowiringInspection", "SpringJavaAutowiredMembersInspection"})
+  @Autowired
+  protected Example example;
+
+  @Test
+  public void testKeyRotation()
+  {
+    final Anubis anubis = tenantApplicationSecurityEnvironment.getAnubis();
+
+    final String systemToken = tenantApplicationSecurityEnvironment.getSystemSecurityEnvironment().systemToken(APP_NAME);
+
+    try (final AutoSeshat ignored1 = new AutoSeshat(systemToken)) {
+      //Create a signature set then test that it is listed.
+      final RsaKeyPairFactory.KeyPairHolder identityManagerKeyPair = RsaKeyPairFactory.createKeyPair();
+      final Signature identityManagerSignature = new Signature(identityManagerKeyPair.getPublicKeyMod(), identityManagerKeyPair.getPublicKeyExp());
+
+      anubis.createSignatureSet(identityManagerKeyPair.getTimestamp(), identityManagerSignature);
+      {
+        final List<String> signatureSets = anubis.getAllSignatureSets();
+        Assert.assertTrue(signatureSets.contains(identityManagerKeyPair.getTimestamp()));
+      }
+
+      //Get the newly created signature set, and test that it's contents are correct.
+      final ApplicationSignatureSet signatureSet = anubis.getSignatureSet(identityManagerKeyPair.getTimestamp());
+      Assert.assertEquals(identityManagerSignature, signatureSet.getIdentityManagerSignature());
+
+      //Get just the application signature, and test that it's contents match the results of the whole signature set.
+      final Signature applicationSignature = anubis.getApplicationSignature(identityManagerKeyPair.getTimestamp());
+      Assert.assertEquals(signatureSet.getApplicationSignature(), applicationSignature);
+
+      //Create a second signature set and test that it and the prevous signature set are listed.
+      final RsaKeyPairFactory.KeyPairHolder identityManagerKeyPair2 = RsaKeyPairFactory.createKeyPair();
+      final Signature identityManagerSignature2 = new Signature(identityManagerKeyPair2.getPublicKeyMod(), identityManagerKeyPair2.getPublicKeyExp());
+
+      anubis.createSignatureSet(identityManagerKeyPair2.getTimestamp(), identityManagerSignature2);
+      {
+        final List<String> signatureSets = anubis.getAllSignatureSets();
+        Assert.assertTrue(signatureSets.contains(identityManagerKeyPair.getTimestamp()));
+        Assert.assertTrue(signatureSets.contains(identityManagerKeyPair2.getTimestamp()));
+      }
+
+      //Get the newly created signature set, and test that it's contents are correct.
+      final ApplicationSignatureSet signatureSet2 = anubis.getSignatureSet(identityManagerKeyPair2.getTimestamp());
+      Assert.assertEquals(identityManagerSignature2, signatureSet2.getIdentityManagerSignature());
+
+      //Delete one of the signature sets and test that it is no longer listed.
+      anubis.deleteSignatureSet(identityManagerKeyPair.getTimestamp());
+      {
+        final List<String> signatureSets = anubis.getAllSignatureSets();
+        Assert.assertFalse(signatureSets.contains(identityManagerKeyPair.getTimestamp()));
+      }
+
+      //Getting the newly deleted signature set should fail.
+      try {
+        anubis.getSignatureSet(identityManagerKeyPair.getTimestamp());
+        Assert.fail("Not found exception should be thrown.");
+      } catch (final NotFoundException ignored) {
+      }
+
+      //Getting the newly deleted application signature set should likewise fail.
+      try {
+        anubis.getApplicationSignature(identityManagerKeyPair.getTimestamp());
+        Assert.fail("Not found exception should be thrown.");
+      } catch (final NotFoundException ignored) {
+      }
+    }
+  }
+}
diff --git a/component-test/src/main/java/TestPermittableEndpoints.java b/component-test/src/main/java/TestPermittableEndpoints.java
index 455cbb4..64a4f4e 100644
--- a/component-test/src/main/java/TestPermittableEndpoints.java
+++ b/component-test/src/main/java/TestPermittableEndpoints.java
@@ -28,6 +28,8 @@
 import org.junit.runner.RunWith;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -41,6 +43,7 @@
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
 public class TestPermittableEndpoints {
   private static final String APP_NAME = "anubis-v1";
+  private static final String LOGGER_QUALIFIER = "test-logger";
 
   @Configuration
   @Import({ExampleConfiguration.class})
@@ -49,12 +52,17 @@
       super();
     }
 
-    @Bean()
+    @Bean(name=LOGGER_QUALIFIER)
     public Logger logger() {
       return LoggerFactory.getLogger("permittable-test-logger");
     }
   }
 
+  @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
+  @Autowired
+  @Qualifier(value = LOGGER_QUALIFIER)
+  Logger logger;
+
   private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
   private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
   private final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer);
@@ -67,7 +75,7 @@
 
   @Test
   public void shouldFindPermittableEndpoints() throws Exception {
-    final Anubis anubis = AnubisApiFactory.create(TestPermittableEndpoints.testEnvironment.serverURI());
+    final Anubis anubis = AnubisApiFactory.create(TestPermittableEndpoints.testEnvironment.serverURI(), logger);
     final List<PermittableEndpoint> permittableEndpoints = anubis.getPermittableEndpoints();
     Assert.assertNotNull(permittableEndpoints);
     Assert.assertEquals(6, permittableEndpoints.size());
diff --git a/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/Example.java b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/Example.java
new file mode 100644
index 0000000..a50edbc
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/Example.java
@@ -0,0 +1,33 @@
+/*
+ * 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.anubis.example.nokeystorage;
+
+import io.mifos.core.api.util.CustomFeignClientsConfiguration;
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@FeignClient(name="anubis-v1", path="/anubis/v1", configuration = CustomFeignClientsConfiguration.class)
+public interface Example {
+  @RequestMapping(value = "initialize", method = RequestMethod.POST)
+  void initialize();
+
+  @RequestMapping(value = "initialize", method = RequestMethod.GET)
+  boolean initialized();
+
+  @RequestMapping(value = "initialize", method = RequestMethod.DELETE)
+  void uninitialize();
+}
diff --git a/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleConfiguration.java b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleConfiguration.java
new file mode 100644
index 0000000..f0ab242
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * 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.anubis.example.nokeystorage;
+
+import io.mifos.anubis.config.EnableAnubis;
+import io.mifos.core.lang.config.EnableServiceException;
+import io.mifos.core.lang.config.EnableTenantContext;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Myrle Krantz
+ */
+@Configuration
+@EnableAutoConfiguration
+@EnableTenantContext
+@EnableAnubis(storeTenantKeysAtInitialization = false)
+@EnableServiceException
+@ComponentScan({
+    "io.mifos.anubis.example.nokeystorage"
+})
+public class ExampleConfiguration {
+}
diff --git a/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleRestController.java b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleRestController.java
new file mode 100644
index 0000000..a88dffa
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/ExampleRestController.java
@@ -0,0 +1,75 @@
+/*
+ * 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.anubis.example.nokeystorage;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
+import io.mifos.anubis.api.v1.domain.Signature;
+import io.mifos.core.lang.security.RsaKeyPairFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@RestController
+@RequestMapping()
+public class ExampleRestController {
+  private boolean initialized = false;
+  private final SpecialTenantSignatureRepository specialTenantSignatureRepository;
+
+  @Autowired
+  public ExampleRestController(final SpecialTenantSignatureRepository specialTenantSignatureRepository) {
+    this.specialTenantSignatureRepository = specialTenantSignatureRepository;
+  }
+
+  @RequestMapping(value = "/initialize", method = RequestMethod.POST)
+  @Permittable(AcceptedTokenType.SYSTEM)
+  public ResponseEntity<Void> initialize()
+  {
+    final RsaKeyPairFactory.KeyPairHolder applicationKeyPair = RsaKeyPairFactory.createKeyPair();
+    final RsaKeyPairFactory.KeyPairHolder identityManagerKeyPair = RsaKeyPairFactory.createKeyPair();
+    final Signature applicationSignature = new Signature(applicationKeyPair.getPublicKeyMod(), applicationKeyPair.getPublicKeyExp());
+    final Signature identityManagerSignature = new Signature(identityManagerKeyPair.getPublicKeyMod(), identityManagerKeyPair.getPublicKeyExp());
+
+    final ApplicationSignatureSet applicationSignatureSet = new ApplicationSignatureSet(identityManagerKeyPair.getTimestamp(), applicationSignature, identityManagerSignature);
+
+    this.specialTenantSignatureRepository.addSignatureSet(applicationSignatureSet);
+    initialized = true;
+    return new ResponseEntity<>(HttpStatus.OK);
+  }
+
+  @RequestMapping(value = "/initialize", method = RequestMethod.GET)
+  @Permittable(AcceptedTokenType.GUEST)
+  public ResponseEntity<Boolean> isInitialized()
+  {
+    return new ResponseEntity<>(initialized, HttpStatus.OK);
+  }
+
+  @RequestMapping(value = "/initialize", method = RequestMethod.DELETE)
+  @Permittable(AcceptedTokenType.GUEST)
+  public ResponseEntity<Void> uninitialize()
+  {
+    initialized = false;
+    return new ResponseEntity<>(HttpStatus.OK);
+  }
+}
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/SpecialTenantSignatureRepository.java b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/SpecialTenantSignatureRepository.java
new file mode 100644
index 0000000..c74903f
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/anubis/example/nokeystorage/SpecialTenantSignatureRepository.java
@@ -0,0 +1,66 @@
+/*
+ * 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.anubis.example.nokeystorage;
+
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
+import io.mifos.anubis.api.v1.domain.Signature;
+import io.mifos.anubis.config.TenantSignatureRepository;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author Myrle Krantz
+ */
+@Component
+public class SpecialTenantSignatureRepository implements TenantSignatureRepository {
+  private final Map<String, ApplicationSignatureSet> applicationSignatureSetMap = new HashMap<>();
+
+  void addSignatureSet(final ApplicationSignatureSet applicationSignatureSet) {
+    applicationSignatureSetMap.put(applicationSignatureSet.getTimestamp(), applicationSignatureSet);
+  }
+
+  @Override
+  public Optional<Signature> getIdentityManagerSignature(final String timestamp) throws IllegalArgumentException {
+    final Optional<ApplicationSignatureSet> sigset = Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
+    return sigset.map(ApplicationSignatureSet::getIdentityManagerSignature);
+  }
+
+  @Override
+  public List<String> getAllSignatureSetKeyTimestamps() {
+    return applicationSignatureSetMap.keySet().stream().collect(Collectors.toList());
+  }
+
+  @Override
+  public Optional<ApplicationSignatureSet> getSignatureSet(final String timestamp) {
+    return Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
+  }
+
+  @Override
+  public void deleteSignatureSet(final String timestamp) {
+    applicationSignatureSetMap.remove(timestamp);
+  }
+
+  @Override
+  public Optional<Signature> getApplicationSignature(final String timestamp) {
+    final Optional<ApplicationSignatureSet> sigset = Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
+    return sigset.map(ApplicationSignatureSet::getApplicationSignature);
+  }
+}
diff --git a/library/src/main/java/io/mifos/anubis/config/AnubisImportSelector.java b/library/src/main/java/io/mifos/anubis/config/AnubisImportSelector.java
index 290da98..7da83f3 100644
--- a/library/src/main/java/io/mifos/anubis/config/AnubisImportSelector.java
+++ b/library/src/main/java/io/mifos/anubis/config/AnubisImportSelector.java
@@ -16,6 +16,7 @@
 package io.mifos.anubis.config;
 
 import io.mifos.anubis.controller.EmptyInitializeResourcesRestController;
+import io.mifos.anubis.controller.SignatureCreatorRestController;
 import io.mifos.anubis.controller.SignatureRestController;
 import io.mifos.anubis.controller.PermittableRestController;
 import io.mifos.anubis.provider.SystemRsaKeyProvider;
@@ -54,6 +55,7 @@
     classesToImport.add(GuestAuthenticator.class);
 
     classesToImport.add(PermittableRestController.class);
+    classesToImport.add(SignatureRestController.class);
     classesToImport.add(PermittableService.class);
 
     final boolean storeTenantKeysAtInitialization = (boolean)importingClassMetadata
@@ -61,7 +63,7 @@
         .get("storeTenantKeysAtInitialization");
 
     if (storeTenantKeysAtInitialization) {
-      classesToImport.add(SignatureRestController.class);
+      classesToImport.add(SignatureCreatorRestController.class);
       classesToImport.add(TenantAuthorizationDataRepository.class);
 
       final boolean generateEmptyInitializeEndpoint = (boolean)importingClassMetadata
diff --git a/library/src/main/java/io/mifos/anubis/config/TenantSignatureProvider.java b/library/src/main/java/io/mifos/anubis/config/TenantSignatureRepository.java
similarity index 73%
rename from library/src/main/java/io/mifos/anubis/config/TenantSignatureProvider.java
rename to library/src/main/java/io/mifos/anubis/config/TenantSignatureRepository.java
index 037fc10..de6b1eb 100644
--- a/library/src/main/java/io/mifos/anubis/config/TenantSignatureProvider.java
+++ b/library/src/main/java/io/mifos/anubis/config/TenantSignatureRepository.java
@@ -16,11 +16,13 @@
 package io.mifos.anubis.config;
 
 
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.Signature;
 
+import java.util.List;
 import java.util.Optional;
 
-public interface TenantSignatureProvider {
+public interface TenantSignatureRepository {
   /**
    *
    * @param timestamp The timestamp of the signature to get.
@@ -28,4 +30,12 @@
    * @throws IllegalArgumentException if the tenant context is not set.
    */
   Optional<Signature> getIdentityManagerSignature(String timestamp) throws IllegalArgumentException;
+
+  List<String> getAllSignatureSetKeyTimestamps();
+
+  Optional<ApplicationSignatureSet> getSignatureSet(String timestamp);
+
+  void deleteSignatureSet(String timestamp);
+
+  Optional<Signature> getApplicationSignature(String timestamp);
 }
diff --git a/library/src/main/java/io/mifos/anubis/controller/SignatureCreatorRestController.java b/library/src/main/java/io/mifos/anubis/controller/SignatureCreatorRestController.java
new file mode 100644
index 0000000..f149a3f
--- /dev/null
+++ b/library/src/main/java/io/mifos/anubis/controller/SignatureCreatorRestController.java
@@ -0,0 +1,62 @@
+/*
+ * 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.anubis.controller;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
+import io.mifos.anubis.api.v1.domain.Signature;
+import io.mifos.anubis.api.v1.validation.ValidKeyTimestamp;
+import io.mifos.anubis.repository.TenantAuthorizationDataRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * @author Myrle Krantz
+ */
+@RestController
+@RequestMapping()
+public class SignatureCreatorRestController {
+
+  private final TenantAuthorizationDataRepository tenantAuthorizationDataRepository;
+
+  @Autowired
+  public SignatureCreatorRestController(final TenantAuthorizationDataRepository tenantAuthorizationDataRepository) {
+    this.tenantAuthorizationDataRepository = tenantAuthorizationDataRepository;
+  }
+
+  @Permittable(AcceptedTokenType.SYSTEM)
+  @RequestMapping(
+          value = "/signatures/{timestamp}",
+          method = RequestMethod.POST,
+          consumes = {MediaType.ALL_VALUE},
+          produces = {MediaType.APPLICATION_JSON_VALUE})
+  public
+  @ResponseBody
+  ResponseEntity<ApplicationSignatureSet> createSignatureSet(
+          @PathVariable("timestamp") @ValidKeyTimestamp final String timestamp,
+          @RequestBody @Valid final Signature identityManagerSignature) {
+    return ResponseEntity.ok(
+            new ApplicationSignatureSet(
+                    timestamp,
+                    tenantAuthorizationDataRepository.createSignatureSet(timestamp, identityManagerSignature),
+                    identityManagerSignature));
+  }
+}
diff --git a/library/src/main/java/io/mifos/anubis/controller/SignatureRestController.java b/library/src/main/java/io/mifos/anubis/controller/SignatureRestController.java
index 53b0d83..af81fe2 100644
--- a/library/src/main/java/io/mifos/anubis/controller/SignatureRestController.java
+++ b/library/src/main/java/io/mifos/anubis/controller/SignatureRestController.java
@@ -19,79 +19,71 @@
 import io.mifos.anubis.annotation.Permittable;
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.Signature;
-import io.mifos.anubis.api.v1.validation.ValidKeyTimestamp;
-import io.mifos.anubis.repository.TenantAuthorizationDataRepository;
+import io.mifos.anubis.config.TenantSignatureRepository;
 import io.mifos.core.lang.ServiceException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
-import javax.validation.Valid;
+import java.util.List;
 
 /**
  * @author Myrle Krantz
  */
 @RestController
-@RequestMapping("/signatures")
+@RequestMapping()
 public class SignatureRestController {
-  final private TenantAuthorizationDataRepository tenantAuthorizationDataRepository;
+  final private TenantSignatureRepository tenantSignatureRepository;
 
   @Autowired
-  public SignatureRestController(
-          final TenantAuthorizationDataRepository tenantAuthorizationDataRepository) {
-    this.tenantAuthorizationDataRepository = tenantAuthorizationDataRepository;
+  public SignatureRestController(final TenantSignatureRepository tenantSignatureRepository) {
+    this.tenantSignatureRepository = tenantSignatureRepository;
   }
 
   @Permittable(AcceptedTokenType.SYSTEM)
   @RequestMapping(
-          value = "/{timestamp}",
-          method = RequestMethod.POST,
+          value = "/signatures",
+          method = RequestMethod.GET,
           consumes = {MediaType.ALL_VALUE},
           produces = {MediaType.APPLICATION_JSON_VALUE})
   public
-  @ResponseBody ResponseEntity<ApplicationSignatureSet> createSignatureSet(
-          @PathVariable("timestamp") @ValidKeyTimestamp final String timestamp,
-          @RequestBody @Valid final Signature identityManagerSignature) {
-    return ResponseEntity.ok(
-            new ApplicationSignatureSet(
-                    timestamp,
-                    tenantAuthorizationDataRepository.createSignatureSet(timestamp, identityManagerSignature),
-                    identityManagerSignature));
+  @ResponseBody ResponseEntity<List<String>> getAllSignatureSets() {
+    return ResponseEntity.ok(tenantSignatureRepository.getAllSignatureSetKeyTimestamps());
   }
 
   @Permittable(AcceptedTokenType.SYSTEM)
-  @RequestMapping(value = "/{timestamp}", method = RequestMethod.GET,
+  @RequestMapping(value = "/signatures/{timestamp}", method = RequestMethod.GET,
           consumes = {MediaType.ALL_VALUE},
           produces = {MediaType.APPLICATION_JSON_VALUE})
   public
   @ResponseBody ResponseEntity<ApplicationSignatureSet> getSignatureSet(@PathVariable("timestamp") final String timestamp)
   {
-    return tenantAuthorizationDataRepository.getSignatureSet(timestamp)
+    return tenantSignatureRepository.getSignatureSet(timestamp)
             .map(ResponseEntity::ok)
             .orElseThrow(() -> ServiceException.notFound("Signature for timestamp '" + timestamp + "' not found."));
   }
 
   @Permittable(AcceptedTokenType.SYSTEM)
-  @RequestMapping(value = "/{timestamp}", method = RequestMethod.DELETE,
+  @RequestMapping(value = "/signatures/{timestamp}", method = RequestMethod.DELETE,
           consumes = {MediaType.ALL_VALUE},
           produces = {MediaType.APPLICATION_JSON_VALUE})
   public
   @ResponseBody ResponseEntity<Void> deleteSignatureSet(@PathVariable("timestamp") final String timestamp)
   {
-    tenantAuthorizationDataRepository.deleteSignatureSet(timestamp);
+    tenantSignatureRepository.deleteSignatureSet(timestamp);
     return ResponseEntity.accepted().build();
   }
 
   @Permittable(AcceptedTokenType.SYSTEM)
-  @RequestMapping(value = "/{timestamp}/application", method = RequestMethod.GET,
+  @RequestMapping(value = "/signatures/{timestamp}/application", method = RequestMethod.GET,
           consumes = {MediaType.ALL_VALUE},
           produces = {MediaType.APPLICATION_JSON_VALUE})
   public
   @ResponseBody ResponseEntity<Signature> getApplicationSignature(@PathVariable("timestamp") final String timestamp)
   {
-    return tenantAuthorizationDataRepository.getApplicationSignature(timestamp)
+    return tenantSignatureRepository.getApplicationSignature(timestamp)
             .map(ResponseEntity::ok)
             .orElseThrow(() -> ServiceException.notFound("Signature for timestamp '" + timestamp + "' not found."));
   }
-}
+}
\ No newline at end of file
diff --git a/library/src/main/java/io/mifos/anubis/provider/TenantRsaKeyProvider.java b/library/src/main/java/io/mifos/anubis/provider/TenantRsaKeyProvider.java
index fda5925..aa3d38f 100644
--- a/library/src/main/java/io/mifos/anubis/provider/TenantRsaKeyProvider.java
+++ b/library/src/main/java/io/mifos/anubis/provider/TenantRsaKeyProvider.java
@@ -16,7 +16,7 @@
 package io.mifos.anubis.provider;
 
 import io.mifos.anubis.api.v1.domain.Signature;
-import io.mifos.anubis.config.TenantSignatureProvider;
+import io.mifos.anubis.config.TenantSignatureRepository;
 import io.mifos.core.lang.security.RsaPublicKeyBuilder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -30,17 +30,17 @@
 @Component
 public class TenantRsaKeyProvider {
 
-  private final TenantSignatureProvider tenantSignatureProvider;
+  private final TenantSignatureRepository tenantSignatureRepository;
 
   @Autowired
-  public TenantRsaKeyProvider(final TenantSignatureProvider tenantSignatureProvider)
+  public TenantRsaKeyProvider(final TenantSignatureRepository tenantSignatureRepository)
   {
-    this.tenantSignatureProvider = tenantSignatureProvider;
+    this.tenantSignatureRepository = tenantSignatureRepository;
   }
 
   public PublicKey getPublicKey(final String keyTimestamp) throws InvalidKeyTimestampException {
     final Optional<Signature> tenantAuthorizationData =
-        tenantSignatureProvider.getIdentityManagerSignature(keyTimestamp);
+        tenantSignatureRepository.getIdentityManagerSignature(keyTimestamp);
 
     return
         tenantAuthorizationData.map(x -> new RsaPublicKeyBuilder()
diff --git a/library/src/main/java/io/mifos/anubis/repository/TenantAuthorizationDataRepository.java b/library/src/main/java/io/mifos/anubis/repository/TenantAuthorizationDataRepository.java
index a59a42c..c6e5c9e 100644
--- a/library/src/main/java/io/mifos/anubis/repository/TenantAuthorizationDataRepository.java
+++ b/library/src/main/java/io/mifos/anubis/repository/TenantAuthorizationDataRepository.java
@@ -18,11 +18,12 @@
 import com.datastax.driver.core.*;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.core.querybuilder.Update;
 import com.datastax.driver.core.schemabuilder.SchemaBuilder;
 import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
 import io.mifos.anubis.api.v1.domain.Signature;
 import io.mifos.anubis.config.AnubisConstants;
-import io.mifos.anubis.config.TenantSignatureProvider;
+import io.mifos.anubis.config.TenantSignatureRepository;
 import io.mifos.core.cassandra.core.CassandraSessionProvider;
 import io.mifos.core.lang.ApplicationName;
 import io.mifos.core.lang.security.RsaKeyPairFactory;
@@ -32,17 +33,22 @@
 import org.springframework.stereotype.Component;
 import org.springframework.util.Assert;
 
+import javax.annotation.Nonnull;
 import java.math.BigInteger;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 /**
  * @author Myrle Krantz
  */
 @Component
-public class TenantAuthorizationDataRepository implements TenantSignatureProvider {
+public class TenantAuthorizationDataRepository implements TenantSignatureRepository {
   private static final String AUTHORIZATION_TABLE_SUFFIX = "_authorization_v1_data";
+  private static final String AUTHORIZATION_INDEX_SUFFIX = "_authorization_v1_valid_index";
   private static final String TIMESTAMP_COLUMN = "timestamp";
   private static final String VALID_COLUMN = "valid";
   private static final String IDENTITY_MANAGER_PUBLIC_KEY_MOD_COLUMN = "identity_manager_public_key_mod";
@@ -53,6 +59,7 @@
   private static final String APPLICATION_PUBLIC_KEY_EXP_COLUMN = "application_public_key_exp";
 
   private final String tableName;
+  private final String indexName;
   private final CassandraSessionProvider cassandraSessionProvider;
 
   //So that the query only has to be prepared once and the Cassandra driver stops writing warnings into my logfiles.
@@ -66,6 +73,7 @@
       final @Qualifier(AnubisConstants.LOGGER_NAME) Logger logger)
   {
     tableName = applicationName.getServiceName() + AUTHORIZATION_TABLE_SUFFIX;
+    indexName = applicationName.getServiceName() + AUTHORIZATION_INDEX_SUFFIX;
     this.cassandraSessionProvider = cassandraSessionProvider;
     this.logger = logger;
   }
@@ -82,6 +90,9 @@
    * for the identity manager.
    */
   public Signature createSignatureSet(final String timestamp, final Signature identityManagerSignature) {
+    Assert.notNull(timestamp);
+    Assert.notNull(identityManagerSignature);
+
     //TODO: add validation to make sure this timestamp is more recent than any already stored.
     final RsaKeyPairFactory.KeyPairHolder applicationSignature = RsaKeyPairFactory.createKeyPair();
 
@@ -101,10 +112,12 @@
   }
 
   public Optional<ApplicationSignatureSet> getSignatureSet(final String timestamp) {
+    Assert.notNull(timestamp);
     return getRow(timestamp).map(TenantAuthorizationDataRepository::mapRowToSignatureSet);
   }
 
   public void deleteSignatureSet(final String timestamp) {
+    Assert.notNull(timestamp);
     //Don't actually delete, just invalidate, so that if someone starts coming at me with an older keyset, I'll
     //know what's happening.
     final Session session = cassandraSessionProvider.getTenantSession();
@@ -112,15 +125,17 @@
   }
 
   public Optional<Signature> getApplicationSignature(final String timestamp) {
+    Assert.notNull(timestamp);
+
     return getRow(timestamp).map(TenantAuthorizationDataRepository::mapRowToApplicationSignature);
   }
 
-  private void createTable(final Session tenantSession) {
+  private void createTable(final @Nonnull Session tenantSession) {
 
     final String createTenantsTable = SchemaBuilder
-        .createTable(tableName)
-        .ifNotExists()
-        .addPartitionKey(TIMESTAMP_COLUMN, DataType.text())
+            .createTable(tableName)
+            .ifNotExists()
+            .addPartitionKey(TIMESTAMP_COLUMN, DataType.text())
             .addColumn(VALID_COLUMN, DataType.cboolean())
             .addColumn(IDENTITY_MANAGER_PUBLIC_KEY_MOD_COLUMN, DataType.varint())
             .addColumn(IDENTITY_MANAGER_PUBLIC_KEY_EXP_COLUMN, DataType.varint())
@@ -128,19 +143,27 @@
             .addColumn(APPLICATION_PRIVATE_KEY_EXP_COLUMN, DataType.varint())
             .addColumn(APPLICATION_PUBLIC_KEY_MOD_COLUMN, DataType.varint())
             .addColumn(APPLICATION_PUBLIC_KEY_EXP_COLUMN, DataType.varint())
-        .buildInternal();
+            .buildInternal();
 
     tenantSession.execute(createTenantsTable);
+
+    final String createValidIndex = SchemaBuilder.createIndex(indexName)
+            .ifNotExists()
+            .onTable(tableName)
+            .andColumn(VALID_COLUMN)
+            .toString();
+
+    tenantSession.execute(createValidIndex);
   }
 
-  private void createEntry(final Session tenantSession,
-                           final String timestamp,
-                           final BigInteger identityManagerPublicKeyModulus,
-                           final BigInteger identityManagerPublicKeyExponent,
-                           final BigInteger applicationPrivateKeyModulus,
-                           final BigInteger applicationPrivateKeyExponent,
-                           final BigInteger applicationPublicKeyModulus,
-                           final BigInteger applicationPublicKeyExponent)
+  private void createEntry(final @Nonnull Session tenantSession,
+                           final @Nonnull String timestamp,
+                           final @Nonnull BigInteger identityManagerPublicKeyModulus,
+                           final @Nonnull BigInteger identityManagerPublicKeyExponent,
+                           final @Nonnull BigInteger applicationPrivateKeyModulus,
+                           final @Nonnull BigInteger applicationPrivateKeyExponent,
+                           final @Nonnull BigInteger applicationPublicKeyModulus,
+                           final @Nonnull BigInteger applicationPublicKeyExponent)
   {
 
     final ResultSet timestampCount =
@@ -196,28 +219,21 @@
     }
   }
 
-  private void invalidateEntry(final Session tenantSession, final String timestamp) {
-    final BoundStatement tenantUpdateStatement =
-            tenantSession.prepare("UPDATE " + tableName + " SET "
-                    + VALID_COLUMN + " = ?, "
-                    + "WHERE " + TIMESTAMP_COLUMN + " = ?").bind();
-
-    tenantUpdateStatement.setString(TIMESTAMP_COLUMN, timestamp);
-    tenantUpdateStatement.setBool(VALID_COLUMN, false);
-
-    tenantSession.execute(tenantUpdateStatement);
+  private void invalidateEntry(final @Nonnull Session tenantSession, final @Nonnull String timestamp) {
+    final Update.Assignments updateQuery = QueryBuilder.update(tableName).where(QueryBuilder.eq(TIMESTAMP_COLUMN, timestamp)).with(QueryBuilder.set(VALID_COLUMN, false));
+    tenantSession.execute(updateQuery);
   }
 
   private void completeBoundStatement(
-      final BoundStatement boundStatement,
-      final String timestamp,
+      final @Nonnull BoundStatement boundStatement,
+      final @Nonnull String timestamp,
       final boolean valid,
-      final BigInteger identityManagerPublicKeyModulus,
-      final BigInteger identityManagerPublicKeyExponent,
-      final BigInteger applicationPrivateKeyModulus,
-      final BigInteger applicationPrivateKeyExponent,
-      final BigInteger applicationPublicKeyModulus,
-      final BigInteger applicationPublicKeyExponent) {
+      final @Nonnull BigInteger identityManagerPublicKeyModulus,
+      final @Nonnull BigInteger identityManagerPublicKeyExponent,
+      final @Nonnull BigInteger applicationPrivateKeyModulus,
+      final @Nonnull BigInteger applicationPrivateKeyExponent,
+      final @Nonnull BigInteger applicationPublicKeyModulus,
+      final @Nonnull BigInteger applicationPublicKeyExponent) {
     boundStatement.setString(TIMESTAMP_COLUMN, timestamp);
     boundStatement.setBool(VALID_COLUMN, valid);
     boundStatement.setVarint(IDENTITY_MANAGER_PUBLIC_KEY_MOD_COLUMN, identityManagerPublicKeyModulus);
@@ -231,10 +247,11 @@
   @Override
   public Optional<Signature> getIdentityManagerSignature(final String timestamp)
   {
+    Assert.notNull(timestamp);
     return getRow(timestamp).map(TenantAuthorizationDataRepository::mapRowToIdentityManagerSignature);
   }
 
-  private Optional<Row> getRow(final String timestamp) {
+  private Optional<Row> getRow(final @Nonnull String timestamp) {
     final Session tenantSession = cassandraSessionProvider.getTenantSession();
     final Select.Where query = timestampToSignatureQueryMap.computeIfAbsent(timestamp, timestampKey ->
             QueryBuilder.select().from(tableName).where(QueryBuilder.eq(TIMESTAMP_COLUMN, timestampKey)));
@@ -247,11 +264,13 @@
     return ret.filter(TenantAuthorizationDataRepository::mapRowToValid);
   }
 
-  private static Boolean mapRowToValid(final Row row) {
+  private static Boolean mapRowToValid(final @Nonnull Row row) {
     return row.get(VALID_COLUMN, Boolean.class);
   }
 
-  private static Signature getSignature(Row row, String publicKeyModColumnName, String publicKeyExpColumnName) {
+  private static Signature getSignature(final @Nonnull Row row,
+                                        final @Nonnull String publicKeyModColumnName,
+                                        final @Nonnull String publicKeyExpColumnName) {
     final BigInteger publicKeyModulus = row.get(publicKeyModColumnName, BigInteger.class);
     final BigInteger publicKeyExponent = row.get(publicKeyExpColumnName, BigInteger.class);
 
@@ -261,19 +280,27 @@
     return new Signature(publicKeyModulus, publicKeyExponent);
   }
 
-  private static Signature mapRowToIdentityManagerSignature(final Row row) {
+  private static Signature mapRowToIdentityManagerSignature(final @Nonnull Row row) {
     return getSignature(row, IDENTITY_MANAGER_PUBLIC_KEY_MOD_COLUMN, IDENTITY_MANAGER_PUBLIC_KEY_EXP_COLUMN);
   }
 
-  private static Signature mapRowToApplicationSignature(final Row row) {
+  private static Signature mapRowToApplicationSignature(final @Nonnull Row row) {
     return getSignature(row, APPLICATION_PUBLIC_KEY_MOD_COLUMN, APPLICATION_PUBLIC_KEY_EXP_COLUMN);
   }
 
-  private static ApplicationSignatureSet mapRowToSignatureSet(final Row row) {
+  private static ApplicationSignatureSet mapRowToSignatureSet(final @Nonnull Row row) {
     final String timestamp = row.get(TIMESTAMP_COLUMN, String.class);
     final Signature identityManagerSignature = mapRowToIdentityManagerSignature(row);
     final Signature applicationSignature = mapRowToApplicationSignature(row);
 
     return new ApplicationSignatureSet(timestamp, applicationSignature, identityManagerSignature);
   }
-}
+
+  public List<String> getAllSignatureSetKeyTimestamps() {
+    final Select.Where selectValid = QueryBuilder.select(TIMESTAMP_COLUMN).from(tableName).where(QueryBuilder.eq(VALID_COLUMN, true));
+    final ResultSet result = cassandraSessionProvider.getTenantSession().execute(selectValid);
+    return StreamSupport.stream(result.spliterator(), false)
+            .map(x -> x.get(TIMESTAMP_COLUMN, String.class))
+            .collect(Collectors.toList());
+  }
+}
\ No newline at end of file
diff --git a/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java b/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
index 32342f1..38363c6 100644
--- a/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
+++ b/test/src/main/java/io/mifos/anubis/test/v1/SystemSecurityEnvironment.java
@@ -57,7 +57,7 @@
  */
 @SuppressWarnings({"WeakerAccess", "unused"})
 public class SystemSecurityEnvironment {
-  private final static String LOGGER_NAME = "anubis-test-logger";
+  final static String LOGGER_NAME = "anubis-test-logger";
 
   private final TenantAccessTokenSerializer tenantAccessTokenSerializer;
   private final SystemAccessTokenSerializer systemAccessTokenSerializer;
diff --git a/test/src/main/java/io/mifos/anubis/test/v1/TenantApplicationSecurityEnvironmentTestRule.java b/test/src/main/java/io/mifos/anubis/test/v1/TenantApplicationSecurityEnvironmentTestRule.java
index 338f382..ea1c1b8 100644
--- a/test/src/main/java/io/mifos/anubis/test/v1/TenantApplicationSecurityEnvironmentTestRule.java
+++ b/test/src/main/java/io/mifos/anubis/test/v1/TenantApplicationSecurityEnvironmentTestRule.java
@@ -25,6 +25,8 @@
 import io.mifos.core.lang.TenantContextHolder;
 import io.mifos.core.test.env.TestEnvironment;
 import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.security.interfaces.RSAPublicKey;
 import java.util.Collections;
@@ -46,6 +48,7 @@
 
   private final SystemSecurityEnvironment systemSecurityEnvironment;
   private final BooleanSupplier waitForInitialize;
+  private final Logger logger;
 
   public TenantApplicationSecurityEnvironmentTestRule(final TestEnvironment testEnvironment) {
     this(testEnvironment, () -> true);
@@ -72,6 +75,7 @@
     this.applicationUri = applicationUri;
     this.systemSecurityEnvironment = systemSecurityEnvironment;
     this.waitForInitialize = waitForInitialize;
+    this.logger = LoggerFactory.getLogger(SystemSecurityEnvironment.LOGGER_NAME);
   }
 
   @Override
@@ -83,7 +87,7 @@
 
   public void initializeTenantInApplication()
   {
-    final Anubis anubis = AnubisApiFactory.create(applicationUri);
+    final Anubis anubis = getAnubis();
 
     final String systemToken = systemSecurityEnvironment.systemToken(applicationName);
 
@@ -97,6 +101,10 @@
       }}
   }
 
+  public Anubis getAnubis() {
+    return AnubisApiFactory.create(applicationUri, logger);
+  }
+
   public SystemSecurityEnvironment getSystemSecurityEnvironment()
   {
     return systemSecurityEnvironment;