knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kris...@apache.org
Subject [knox] branch master updated: KNOX-1820 - Cleanup KeystoreService implementations and add unit tests (#72)
Date Thu, 14 Mar 2019 22:36:06 GMT
This is an automated email from the ASF dual-hosted git repository.

krisden pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new 399bb65  KNOX-1820 - Cleanup KeystoreService implementations and add unit tests (#72)
399bb65 is described below

commit 399bb6584c05a7c1307a900e33b324bbd20373a8
Author: Robert Levas <rlevas@apache.org>
AuthorDate: Thu Mar 14 18:36:00 2019 -0400

    KNOX-1820 - Cleanup KeystoreService implementations and add unit tests (#72)
---
 .../org/apache/knox/gateway/GatewayMessages.java   |   5 +
 .../security/impl/DefaultKeystoreService.java      | 195 ++++++--
 .../security/impl/DefaultKeystoreServiceTest.java  | 489 ++++++++++++++++++++-
 .../knox/gateway/i18n/GatewaySpiMessages.java      |  15 -
 .../security/impl/BaseKeystoreService.java         | 178 --------
 .../services/security/impl/CMFKeystoreService.java | 149 -------
 .../security/impl/CMFKeystoreServiceTest.java      | 153 -------
 7 files changed, 622 insertions(+), 562 deletions(-)

diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
index 1aef1c3..1362455 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
@@ -635,4 +635,9 @@ public interface GatewayMessages {
   @Message( level = MessageLevel.ERROR, text = "The path to the keystore is not accessible: {0}" )
   void keystoreFileIsNotAccessible(String path);
 
+  @Message( level = MessageLevel.ERROR, text = "Failed to add credential: {1}" )
+  void failedToAddCredential( @StackTrace( level = MessageLevel.DEBUG ) Exception e );
+
+  @Message(level = MessageLevel.ERROR, text = "Failed to remove credential: {1}")
+  void failedToRemoveCredential(@StackTrace(level = MessageLevel.DEBUG) Exception e);
 }
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
index a681bed..97889fc 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
@@ -17,6 +17,8 @@
  */
 package org.apache.knox.gateway.services.security.impl;
 
+import static org.apache.knox.gateway.services.security.AliasService.NO_CLUSTER_NAME;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.knox.gateway.GatewayMessages;
 import org.apache.knox.gateway.GatewayResources;
@@ -27,12 +29,15 @@ import org.apache.knox.gateway.services.Service;
 import org.apache.knox.gateway.services.ServiceLifecycleException;
 import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.services.security.KeystoreServiceException;
+import org.apache.knox.gateway.services.security.MasterService;
 import org.apache.knox.gateway.util.X509CertificateUtil;
 
-import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.InetAddress;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.GeneralSecurityException;
@@ -55,13 +60,13 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import static org.apache.knox.gateway.services.security.AliasService.NO_CLUSTER_NAME;
+import javax.crypto.spec.SecretKeySpec;
 
-public class DefaultKeystoreService extends BaseKeystoreService implements
-    KeystoreService, Service {
+public class DefaultKeystoreService implements KeystoreService, Service {
 
-  private static final String dnTemplate = "CN={0},OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
+  private static final String DN_TEMPLATE = "CN={0},OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
   private static final String CREDENTIALS_SUFFIX = "-credentials.jceks";
+  private static final String CREDENTIALS_STORE_TYPE = "JCEKS";
   private static final String CERT_GEN_MODE = "hadoop.gateway.cert.gen.mode";
   private static final String CERT_GEN_MODE_LOCALHOST = "localhost";
   private static final String CERT_GEN_MODE_HOSTNAME = "hostname";
@@ -73,6 +78,13 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
   private Lock readLock;
   private Lock writeLock;
 
+  private MasterService masterService;
+  private Path keyStoreDirPath;
+
+  public void setMasterService(MasterService ms) {
+    this.masterService = ms;
+  }
+
   @Override
   public void init(GatewayConfig config, Map<String, String> options)
       throws ServiceLifecycleException {
@@ -82,11 +94,14 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
 
     this.config = config;
 
-    this.keyStoreDir = config.getGatewayKeystoreDir();
-    File ksd = new File(this.keyStoreDir);
-    if (!ksd.exists()) {
-      if( !ksd.mkdirs() ) {
-        throw new ServiceLifecycleException( RES.failedToCreateKeyStoreDirectory( ksd.getAbsolutePath() ) );
+    this.keyStoreDirPath = Paths.get(config.getGatewayKeystoreDir());
+    if (Files.notExists(keyStoreDirPath)) {
+      try {
+        // This will attempt to create all missing directories.  No failures will occur if the
+        // directories already exist.
+        Files.createDirectories(keyStoreDirPath);
+      } catch (IOException e) {
+        throw new ServiceLifecycleException(RES.failedToCreateKeyStoreDirectory(keyStoreDirPath.toString()));
       }
     }
   }
@@ -103,8 +118,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
   public void createKeystoreForGateway() throws KeystoreServiceException {
     writeLock.lock();
     try {
-      String filename = getKeystorePath();
-      createKeystore(filename, config.getIdentityKeystoreType(), getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
+      createKeyStore(Paths.get(config.getIdentityKeystorePath()), config.getIdentityKeystoreType(), getKeyStorePassword(config.getIdentityKeystorePasswordAlias()));
     } finally {
       writeLock.unlock();
     }
@@ -137,7 +151,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
     String keyStoreType;
     String passwordAlias;
     if(keystoreName != null) {
-      keyStoreFile = Paths.get(keyStoreDir, keystoreName + ".jks");
+      keyStoreFile = keyStoreDirPath.resolve(keystoreName + ".jks");
       keyStoreType = "jks";
       passwordAlias = null;
     } else {
@@ -187,8 +201,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
             passphrase,
             new java.security.cert.Certificate[]{cert});
 
-        writeKeystoreToFile(privateKS, new File( config.getIdentityKeystorePath() ), getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
-        //writeCertificateToFile( cert, new File( keyStoreDir + alias + ".pem" ) );
+        writeKeyStoreToFile(privateKS, Paths.get(config.getIdentityKeystorePath()), getKeyStorePassword(config.getIdentityKeystorePasswordAlias()));
       } catch (GeneralSecurityException | IOException e) {
         LOG.failedToAddSeflSignedCertForGateway( alias, e );
         throw new KeystoreServiceException(e);
@@ -200,7 +213,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
   }
 
   private String buildDistinguishedName(String hostname) {
-    MessageFormat headerFormatter = new MessageFormat(dnTemplate, Locale.ROOT);
+    MessageFormat headerFormatter = new MessageFormat(DN_TEMPLATE, Locale.ROOT);
     String[] paramArray = new String[1];
     paramArray[0] = hostname;
     return headerFormatter.format(paramArray);
@@ -208,10 +221,10 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
 
   @Override
   public void createCredentialStoreForCluster(String clusterName) throws KeystoreServiceException {
-    String filename = Paths.get(keyStoreDir, clusterName + CREDENTIALS_SUFFIX).toString();
+    Path keystoreFilePath = keyStoreDirPath.resolve(clusterName + CREDENTIALS_SUFFIX);
     writeLock.lock();
     try {
-      createKeystore(filename, "JCEKS", masterService.getMasterSecret());
+      createKeyStore(keystoreFilePath, CREDENTIALS_STORE_TYPE, masterService.getMasterSecret());
     }
     finally {
       writeLock.unlock();
@@ -221,11 +234,11 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
   @Override
   public boolean isCredentialStoreForClusterAvailable(String clusterName) throws KeystoreServiceException {
     boolean rc;
-    final File  keyStoreFile = new File( keyStoreDir, clusterName + CREDENTIALS_SUFFIX  );
+    final Path keyStoreFilePath = keyStoreDirPath.resolve(clusterName + CREDENTIALS_SUFFIX);
     readLock.lock();
     try {
       try {
-        rc = isKeystoreAvailable(keyStoreFile, "JCEKS", masterService.getMasterSecret());
+        rc = isKeyStoreAvailable(keyStoreFilePath, CREDENTIALS_STORE_TYPE, masterService.getMasterSecret());
       } catch (KeyStoreException | IOException e) {
         throw new KeystoreServiceException(e);
       }
@@ -238,18 +251,13 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
 
   @Override
   public boolean isKeystoreForGatewayAvailable() throws KeystoreServiceException {
-    boolean rc;
-    final File  keyStoreFile = new File( config.getIdentityKeystorePath() );
+    final Path keyStoreFilePath = Paths.get(config.getIdentityKeystorePath());
     readLock.lock();
     try {
-      try {
-        rc = isKeystoreAvailable(keyStoreFile, config.getIdentityKeystoreType(), getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
-      } catch (KeyStoreException | IOException e) {
-        throw new KeystoreServiceException(e);
-      }
-      return rc;
-    }
-    finally {
+      return isKeyStoreAvailable(keyStoreFilePath, config.getIdentityKeystoreType(), getKeyStorePassword(config.getIdentityKeystorePasswordAlias()));
+    } catch (KeyStoreException | IOException e) {
+      throw new KeystoreServiceException(e);
+    } finally {
       readLock.unlock();
     }
   }
@@ -323,7 +331,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
       throws KeystoreServiceException {
     // Do not fail getting the credential store if the keystore file does not exist.  The returned
     // KeyStore will be empty.  This seems like a potential bug, but is the behavior before KNOX-1812
-    return getKeystore(Paths.get(keyStoreDir, clusterName + CREDENTIALS_SUFFIX), "JCEKS", null, false);
+    return getKeystore(keyStoreDirPath.resolve(clusterName + CREDENTIALS_SUFFIX), CREDENTIALS_STORE_TYPE, null, false);
   }
 
   @Override
@@ -334,9 +342,9 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
       removeFromCache(clusterName, alias);
       KeyStore ks = getCredentialStoreForCluster(clusterName);
       addCredential(alias, value, ks);
-      final File  keyStoreFile = new File( keyStoreDir, clusterName + CREDENTIALS_SUFFIX  );
+      final Path keyStoreFilePath = keyStoreDirPath.resolve(clusterName + CREDENTIALS_SUFFIX);
       try {
-        writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
+        writeKeyStoreToFile(ks, keyStoreFilePath, masterService.getMasterSecret());
       } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) {
         LOG.failedToAddCredentialForCluster( clusterName, e );
       }
@@ -379,19 +387,18 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
 
   @Override
   public void removeCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException {
-    final File  keyStoreFile = new File( keyStoreDir, clusterName + CREDENTIALS_SUFFIX  );
+    final Path keyStoreFilePath = keyStoreDirPath.resolve(clusterName + CREDENTIALS_SUFFIX);
     writeLock.lock();
     try {
       removeFromCache(clusterName, alias);
       KeyStore ks = getCredentialStoreForCluster(clusterName);
       removeCredential(alias, ks);
       try {
-        writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
+        writeKeyStoreToFile(ks, keyStoreFilePath, masterService.getMasterSecret());
       } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) {
         LOG.failedToRemoveCredentialForCluster(clusterName, e);
       }
-    }
-    finally {
+    } finally {
       writeLock.unlock();
     }
   }
@@ -442,7 +449,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
    * <p>
    * if <code>failIfNotAccessible</code> is <code>true</code>, then the path to the keystore file
    * (keystorePath) is validated such that it exists, is a file and can be read by the process. If
-   * any of these checks fail, a {@link KeystoreServiceException} is thrown in dicatating the exact
+   * any of these checks fail, a {@link KeystoreServiceException} is thrown in dictating the exact
    * reason.
    * <p>
    * Before the keystore file is loaded, the service's read lock is locked to prevent concurrent
@@ -450,36 +457,128 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
    *
    * @param keystorePath        the path to the keystore file
    * @param keystoreType        the type of keystore file
-   * @param alias               the alias for the password to the keystore file (see {@link #getKeystorePassword(String)})
+   * @param alias               the alias for the password to the keystore file (see {@link #getKeyStorePassword(String)})
    * @param failIfNotAccessible <code>true</code> to ensure the keystore file exists and is readable; <code>false</code> to not check
    * @return a {@link KeyStore}, or <code>null</code> if the requested keystore cannot be created
    * @throws KeystoreServiceException if an error occurs loading the keystore file
    */
   private KeyStore getKeystore(Path keystorePath, String keystoreType, String alias, boolean failIfNotAccessible) throws KeystoreServiceException {
-    File keystoreFile = keystorePath.toFile();
 
     if (failIfNotAccessible) {
-      if (!keystoreFile.exists()) {
+      if (Files.notExists(keystorePath)) {
         LOG.keystoreFileDoesNotExist(keystorePath.toString());
-        throw new KeystoreServiceException("The keystore file does not exist: " + keystoreFile.getAbsolutePath());
-      } else if (!keystoreFile.isFile()) {
+        throw new KeystoreServiceException("The keystore file does not exist: " + keystorePath.toString());
+      } else if (!Files.isRegularFile(keystorePath)) {
         LOG.keystoreFileIsNotAFile(keystorePath.toString());
-        throw new KeystoreServiceException("The keystore file is not a file: " + keystoreFile.getAbsolutePath());
-      } else if (!keystoreFile.canRead()) {
+        throw new KeystoreServiceException("The keystore file is not a file: " + keystorePath.toString());
+      } else if (!Files.isReadable(keystorePath)) {
         LOG.keystoreFileIsNotAccessible(keystorePath.toString());
-        throw new KeystoreServiceException("The keystore file cannot be read: " + keystoreFile.getAbsolutePath());
+        throw new KeystoreServiceException("The keystore file cannot be read: " + keystorePath.toString());
       }
     }
 
     readLock.lock();
     try {
-      return getKeystore(keystoreFile, keystoreType, getKeystorePassword(alias));
+      return loadKeyStore(keystorePath, keystoreType, getKeyStorePassword(alias));
     } finally {
       readLock.unlock();
     }
   }
 
-  private char[] getKeystorePassword(String alias) throws KeystoreServiceException {
+  private boolean isKeyStoreAvailable(final Path keyStoreFilePath, String storeType, char[] password) throws KeyStoreException, IOException {
+    if (Files.exists(keyStoreFilePath)) {
+      try (InputStream input = Files.newInputStream(keyStoreFilePath)) {
+        final KeyStore keyStore = KeyStore.getInstance(storeType);
+        keyStore.load(input, password);
+        return true;
+      } catch (NoSuchAlgorithmException | CertificateException e) {
+        LOG.failedToLoadKeystore(keyStoreFilePath.toString(), storeType, e);
+      } catch (IOException | KeyStoreException e) {
+        LOG.failedToLoadKeystore(keyStoreFilePath.toString(), storeType, e);
+        throw e;
+      }
+    }
+    return false;
+  }
+
+  // Package private for unit test access
+  KeyStore createKeyStore(Path keystoreFilePath, String keystoreType, char[] password) throws KeystoreServiceException {
+    if (Files.notExists(keystoreFilePath)) {
+      // Ensure the parent directory exists...
+      try {
+        // This will attempt to create all missing directories.  No failures will occur if the
+        // directories already exist.
+        Files.createDirectories(keystoreFilePath.getParent());
+      } catch (IOException e) {
+        LOG.failedToCreateKeystore(keystoreFilePath.toString(), keystoreType, e);
+        throw new KeystoreServiceException(e);
+      }
+    }
+
+    try (OutputStream out = Files.newOutputStream(keystoreFilePath)) {
+      KeyStore ks = KeyStore.getInstance(keystoreType);
+      ks.load(null, null);
+      ks.store(out, password);
+      return ks;
+    } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) {
+      LOG.failedToCreateKeystore(keystoreFilePath.toString(), keystoreType, e);
+      throw new KeystoreServiceException(e);
+    }
+  }
+
+  private void addCredential(String alias, String value, KeyStore ks) {
+    if (ks != null) {
+      try {
+        final Key key = new SecretKeySpec(value.getBytes(StandardCharsets.UTF_8), "AES");
+        ks.setKeyEntry(alias, key, masterService.getMasterSecret(), null);
+      } catch (KeyStoreException e) {
+        LOG.failedToAddCredential(e);
+      }
+    }
+  }
+
+  private void removeCredential(String alias, KeyStore ks) {
+    if (ks != null) {
+      try {
+        if (ks.containsAlias(alias)) {
+          ks.deleteEntry(alias);
+        }
+      } catch (KeyStoreException e) {
+        LOG.failedToRemoveCredential(e);
+      }
+    }
+  }
+
+  // Package private for unit test access
+  KeyStore loadKeyStore(final Path keyStoreFilePath, final String storeType, final char[] password) throws KeystoreServiceException {
+    try {
+      final KeyStore keyStore = KeyStore.getInstance(storeType);
+
+      // If the file does not exist, create an empty keystore
+      if (Files.exists(keyStoreFilePath)) {
+        try (InputStream input = Files.newInputStream(keyStoreFilePath)) {
+          keyStore.load(input, password);
+        }
+      } else {
+        keyStore.load(null, password);
+      }
+      return keyStore;
+    } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
+      LOG.failedToLoadKeystore(keyStoreFilePath.toString(), storeType, e);
+      throw new KeystoreServiceException(e);
+    }
+  }
+
+  // Package private for unit test access
+  void writeKeyStoreToFile(final KeyStore keyStore, final Path path, char[] password)
+      throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+    // TODO: backup the keystore on disk before attempting a write and restore on failure
+    try (OutputStream out = Files.newOutputStream(path)) {
+      keyStore.store(out, password);
+    }
+  }
+
+  private char[] getKeyStorePassword(String alias) throws KeystoreServiceException {
     char[] password = null;
     if (StringUtils.isNotEmpty(alias)) {
       password = getCredentialForCluster(NO_CLUSTER_NAME, alias);
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreServiceTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreServiceTest.java
index 52efc40..ebfdc57 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreServiceTest.java
@@ -20,6 +20,13 @@
 
 package org.apache.knox.gateway.services.security.impl;
 
+import static org.apache.knox.gateway.config.GatewayConfig.IDENTITY_KEYSTORE_PASSWORD_ALIAS;
+import static org.apache.knox.gateway.config.GatewayConfig.IDENTITY_KEYSTORE_PATH;
+import static org.apache.knox.gateway.config.GatewayConfig.IDENTITY_KEYSTORE_TYPE;
+import static org.apache.knox.gateway.config.GatewayConfig.IDENTITY_KEY_ALIAS;
+import static org.apache.knox.gateway.config.GatewayConfig.IDENTITY_KEY_PASSPHRASE_ALIAS;
+import static org.apache.knox.gateway.config.GatewayConfig.SIGNING_KEYSTORE_NAME;
+import static org.apache.knox.gateway.config.GatewayConfig.SIGNING_KEY_ALIAS;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.createMockBuilder;
 import static org.easymock.EasyMock.createNiceMock;
@@ -28,20 +35,42 @@ import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
+import org.apache.knox.gateway.services.ServiceLifecycleException;
 import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.services.security.MasterService;
+import org.apache.knox.gateway.util.X509CertificateUtil;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
-import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.util.Collections;
+import java.util.Locale;
 
 public class DefaultKeystoreServiceTest {
   @Rule
@@ -49,10 +78,10 @@ public class DefaultKeystoreServiceTest {
 
   @Test
   public void testGetTruststoreForHttpClientDefaults() throws Exception {
-    final File dataDir = testFolder.newFolder();
+    final Path dataDir = testFolder.newFolder().toPath();
 
     GatewayConfigImpl config = new GatewayConfigImpl();
-    config.set("gateway.data.dir", dataDir.getAbsolutePath());
+    config.set("gateway.data.dir", dataDir.toString());
 
     KeyStore keystore = createNiceMock(KeyStore.class);
 
@@ -72,25 +101,25 @@ public class DefaultKeystoreServiceTest {
 
   @Test
   public void testGetTruststoreForHttpClientCustomTrustStore() throws Exception {
-    final File dataDir = testFolder.newFolder();
-    final File truststoreFile = testFolder.newFile();
+    final Path dataDir = testFolder.newFolder().toPath();
+    final Path truststoreFile = testFolder.newFile().toPath();
     final String truststoreType = "jks";
     final String truststorePasswordAlias = "password-alias";
     final char[] truststorePassword = "truststore_password".toCharArray();
 
     GatewayConfigImpl config = new GatewayConfigImpl();
-    config.set("gateway.data.dir", dataDir.getAbsolutePath());
-    config.set("gateway.httpclient.truststore.path", truststoreFile.getAbsolutePath());
+    config.set("gateway.data.dir", dataDir.toString());
+    config.set("gateway.httpclient.truststore.path", truststoreFile.toString());
     config.set("gateway.httpclient.truststore.type", truststoreType);
     config.set("gateway.httpclient.truststore.password.alias", truststorePasswordAlias);
 
     KeyStore keystore = createNiceMock(KeyStore.class);
 
     DefaultKeystoreService keystoreService = createMockBuilder(DefaultKeystoreService.class)
-        .addMockedMethod("getKeystore", File.class, String.class, char[].class)
+        .addMockedMethod("loadKeyStore", Path.class, String.class, char[].class)
         .addMockedMethod("getCredentialForCluster", String.class, String.class)
         .createMock();
-    expect(keystoreService.getKeystore(eq(truststoreFile), eq(truststoreType), eq(truststorePassword)))
+    expect(keystoreService.loadKeyStore(eq(truststoreFile), eq(truststoreType), eq(truststorePassword)))
         .andReturn(keystore)
         .once();
     expect(keystoreService.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq(truststorePasswordAlias)))
@@ -108,19 +137,18 @@ public class DefaultKeystoreServiceTest {
 
   @Test(expected = KeystoreServiceException.class)
   public void testGetTruststoreForHttpClientMissingCustomTrustStore() throws Exception {
-    final File dataDir = testFolder.newFolder();
+    final Path dataDir = testFolder.newFolder().toPath();
     final String truststoreType = "jks";
     final String truststorePasswordAlias = "password-alias";
     final char[] truststorePassword = "truststore_password".toCharArray();
 
     GatewayConfigImpl config = new GatewayConfigImpl();
-    config.set("gateway.data.dir", dataDir.getAbsolutePath());
-    config.set("gateway.httpclient.truststore.path", Paths.get(dataDir.getAbsolutePath(), "missing_file.jks").toString());
+    config.set("gateway.data.dir", dataDir.toString());
+    config.set("gateway.httpclient.truststore.path", Paths.get(dataDir.toString(), "missing_file.jks").toString());
     config.set("gateway.httpclient.truststore.type", truststoreType);
     config.set("gateway.httpclient.truststore.password.alias", truststorePasswordAlias);
 
     DefaultKeystoreService keystoreService = createMockBuilder(DefaultKeystoreService.class)
-        .addMockedMethod("getKeystore", File.class, String.class, char[].class)
         .addMockedMethod("getCredentialForCluster", String.class, String.class)
         .createMock();
     expect(keystoreService.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq(truststorePasswordAlias)))
@@ -138,24 +166,24 @@ public class DefaultKeystoreServiceTest {
 
   @Test
   public void testGetTruststoreForHttpClientCustomTrustStoreMissingPasswordAlias() throws Exception {
-    final File dataDir = testFolder.newFolder();
-    final File truststoreFile = testFolder.newFile();
+    final Path dataDir = testFolder.newFolder().toPath();
+    final Path truststoreFile = testFolder.newFile().toPath();
     final String truststoreType = "jks";
     final char[] masterSecret = "master_secret".toCharArray();
 
     GatewayConfigImpl config = new GatewayConfigImpl();
-    config.set("gateway.data.dir", dataDir.getAbsolutePath());
-    config.set("gateway.httpclient.truststore.path", truststoreFile.getAbsolutePath());
+    config.set("gateway.data.dir", dataDir.toString());
+    config.set("gateway.httpclient.truststore.path", truststoreFile.toString());
     config.set("gateway.httpclient.truststore.type", truststoreType);
 
     KeyStore keystore = createNiceMock(KeyStore.class);
 
     DefaultKeystoreService keystoreService = createMockBuilder(DefaultKeystoreService.class)
-        .addMockedMethod("getKeystore", File.class, String.class, char[].class)
+        .addMockedMethod("loadKeyStore", Path.class, String.class, char[].class)
         .addMockedMethod("getCredentialForCluster", String.class, String.class)
         .withConstructor()
         .createMock();
-    expect(keystoreService.getKeystore(eq(truststoreFile), eq(truststoreType), eq(masterSecret)))
+    expect(keystoreService.loadKeyStore(eq(truststoreFile), eq(truststoreType), eq(masterSecret)))
         .andReturn(keystore)
         .once();
     expect(keystoreService.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq(GatewayConfig.DEFAULT_HTTP_CLIENT_TRUSTSTORE_PASSWORD_ALIAS)))
@@ -175,4 +203,427 @@ public class DefaultKeystoreServiceTest {
     verify(keystore, keystoreService, masterService);
   }
 
+  @Test
+  public void testKeystoreForGateway() throws Exception {
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    char[] keyPassword = "key_password".toCharArray();
+    char[] customKeyPassword = "custom-key-passphrase".toCharArray();
+    char[] customKeystorePassword = "custom-keystore-password".toCharArray();
+
+    DefaultKeystoreService keystoreServiceAlt = createMockBuilder(DefaultKeystoreService.class)
+        .addMockedMethod("getCredentialForCluster", String.class, String.class)
+        .createMock();
+    expect(keystoreServiceAlt.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq("custom_key_passphrase_alias")))
+        .andReturn(customKeyPassword)
+        .anyTimes();
+    expect(keystoreServiceAlt.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq("custom_keystore_password_alias")))
+        .andReturn(customKeystorePassword)
+        .anyTimes();
+
+    replay(keystoreServiceAlt, masterService);
+
+    Path baseDir = testFolder.newFolder().toPath();
+    GatewayConfigImpl config = createGatewayConfig(baseDir);
+
+    /* *******************
+     * Test Defaults
+     */
+    Path defaultKeystoreFile = baseDir.resolve("security").resolve("keystores").resolve("gateway.jks");
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.setMasterService(masterService);
+    keystoreService.init(config, Collections.emptyMap());
+
+    testCreateGetAndCheckKeystoreForGateway(keystoreService,
+        defaultKeystoreFile,
+        GatewayConfigImpl.DEFAULT_IDENTITY_KEY_ALIAS,
+        keyPassword, config);
+
+
+    /* *******************
+     * Test Custom Values
+     */
+    Path customKeystoreFile = baseDir.resolve("test").resolve("keystore").resolve("custom_keystore.p12");
+    String customKeystoreType = "pkcs12";
+    String customAlias = "custom_alias";
+
+    config.set(IDENTITY_KEYSTORE_PATH, customKeystoreFile.toAbsolutePath().toString());
+    config.set(IDENTITY_KEYSTORE_TYPE, customKeystoreType);
+    config.set(IDENTITY_KEYSTORE_PASSWORD_ALIAS, "custom_keystore_password_alias");
+    config.set(IDENTITY_KEY_ALIAS, customAlias);
+    config.set(IDENTITY_KEY_PASSPHRASE_ALIAS, "custom_key_passphrase_alias");
+
+    keystoreServiceAlt.setMasterService(masterService);
+
+
+    keystoreServiceAlt.init(config, Collections.emptyMap());
+    keystoreServiceAlt.init(config, Collections.emptyMap());
+
+    testCreateGetAndCheckKeystoreForGateway(keystoreServiceAlt, customKeystoreFile, customAlias, customKeyPassword, config);
+
+    // Verify the keystore passwords are set properly...
+    assertTrue(Files.exists(defaultKeystoreFile));
+    assertNotNull(keystoreService.loadKeyStore(defaultKeystoreFile, GatewayConfigImpl.DEFAULT_IDENTITY_KEYSTORE_TYPE, masterPassword));
+    assertTrue(Files.exists(customKeystoreFile));
+    assertNotNull(keystoreService.loadKeyStore(customKeystoreFile, customKeystoreType, customKeystorePassword));
+
+    verify(keystoreServiceAlt, masterService);
+  }
+
+  @Test
+  public void testSigningKeystore() throws Exception {
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    DefaultKeystoreService keystoreServiceAlt = createMockBuilder(DefaultKeystoreService.class)
+        .addMockedMethod("getCredentialForCluster", String.class, String.class)
+        .createMock();
+    expect(keystoreServiceAlt.getCredentialForCluster(eq(AliasService.NO_CLUSTER_NAME), eq(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS)))
+        .andReturn(null)
+        .atLeastOnce();
+
+    replay(keystoreServiceAlt, masterService);
+
+    Path baseDir = testFolder.newFolder().toPath();
+    GatewayConfigImpl config = createGatewayConfig(baseDir);
+
+    /* *******************
+     * Test Defaults
+     */
+    Path defaultFile = baseDir.resolve("security").resolve("keystores").resolve("gateway.jks");
+    String defaultAlias = "gateway-identity";
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.setMasterService(masterService);
+
+    try {
+      keystoreService.init(config, Collections.emptyMap());
+    } catch (ServiceLifecycleException e) {
+      fail("Not expecting ServiceLifecycleException due to missing signing keystore file since a custom one is not specified");
+    }
+
+    createKeystore(keystoreService, defaultFile, defaultAlias, masterPassword);
+
+    keystoreService.init(config, Collections.emptyMap());
+
+    testSigningKeystore(keystoreService, defaultFile, defaultAlias, masterPassword);
+
+    /* *******************
+     * Test Custom Values
+     */
+    String customFileName = "custom_signing.jks";
+    Path customFile = baseDir.resolve("security").resolve("keystores").resolve(customFileName);
+    String customKeyAlias = "custom_alias";
+
+    config.set(SIGNING_KEYSTORE_NAME, customFileName);
+    config.set(SIGNING_KEY_ALIAS, customKeyAlias);
+
+    keystoreServiceAlt.setMasterService(masterService);
+
+    // Ensure the signing keystore exists before init-ing the keystore service
+    createKeystore(keystoreService, customFile, customKeyAlias, masterPassword);
+
+    keystoreServiceAlt.init(config, Collections.emptyMap());
+
+    testSigningKeystore(keystoreServiceAlt, customFile, customKeyAlias, masterPassword);
+
+    // Verify the keystore passwords are set properly...
+    assertTrue(Files.exists(defaultFile));
+    assertNotNull(keystoreService.loadKeyStore(defaultFile, "JKS", masterPassword));
+    assertTrue(Files.exists(customFile));
+    assertNotNull(keystoreService.loadKeyStore(customFile, "JKS", masterPassword));
+
+    verify(keystoreServiceAlt, masterService);
+  }
+
+  @Test
+  public void testCredentialsForCluster() throws Exception {
+    String clusterName = "my_cluster";
+    String credentialAlias = "my_alias";
+    String credentialValue = "my_value";
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    Path baseFolder = testFolder.newFolder().toPath();
+    GatewayConfig config = createGatewayConfig(baseFolder);
+    Path expectedFile = Paths.get(config.getGatewayKeystoreDir(), clusterName + "-credentials.jceks");
+
+    replay(masterService);
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.setMasterService(masterService);
+    keystoreService.init(config, Collections.emptyMap());
+
+    assertFalse(Files.exists(expectedFile));
+    assertFalse(keystoreService.isCredentialStoreForClusterAvailable(clusterName));
+
+    // This should be an empty keystore...
+    KeyStore emptyKeystore = keystoreService.getCredentialStoreForCluster(clusterName);
+    assertNotNull(emptyKeystore);
+    assertEquals(0, emptyKeystore.size());
+
+    keystoreService.createCredentialStoreForCluster(clusterName);
+
+    assertTrue(Files.exists(expectedFile));
+    assertTrue(keystoreService.isCredentialStoreForClusterAvailable(clusterName));
+
+    KeyStore credentialStore = keystoreService.getCredentialStoreForCluster(clusterName);
+    assertNotNull(credentialStore);
+    assertEquals(0, credentialStore.size());
+
+    keystoreService.addCredentialForCluster(clusterName, credentialAlias, credentialValue);
+
+    // The previous version of the credential store was not updated
+    assertEquals(0, credentialStore.size());
+
+    // Get the updated credential store
+    credentialStore = keystoreService.getCredentialStoreForCluster(clusterName);
+    assertNotNull(credentialStore);
+    assertEquals(1, credentialStore.size());
+
+    // Make sure the expected alias and value exists in the credential store
+    Key key = credentialStore.getKey(credentialAlias, masterPassword);
+    assertNotNull(key);
+    assertEquals(credentialValue, new String(key.getEncoded(), StandardCharsets.UTF_8));
+
+    // A request for a existing alias should return the expected value
+    char[] keyValue = keystoreService.getCredentialForCluster(clusterName, credentialAlias);
+    assertNotNull(keyValue);
+    assertEquals(credentialValue, new String(keyValue));
+
+    // A request for an alias that does not exists, should return NULL
+    assertNull(keystoreService.getCredentialForCluster(clusterName, "not!my_alias"));
+
+    // Remove that credential
+    keystoreService.removeCredentialForCluster(clusterName, credentialAlias);
+
+    // Get the updated credential store
+    credentialStore = keystoreService.getCredentialStoreForCluster(clusterName);
+    assertNotNull(credentialStore);
+    assertEquals(0, credentialStore.size());
+
+    // Make sure the expected alias does not exist in the credential store
+    key = credentialStore.getKey(credentialAlias, masterPassword);
+    assertNull(key);
+
+    // A request for a existing alias should return null
+    assertNull(keystoreService.getCredentialForCluster(clusterName, credentialAlias));
+
+    verify(masterService);
+  }
+
+  @Test
+  public void testAddSelfSignedCertForGatewayLocalhost() throws Exception {
+    testAddSelfSignedCertForGateway(null);
+  }
+
+  @Test
+  public void testAddSelfSignedCertForGatewayExplicitHostname() throws Exception {
+    testAddSelfSignedCertForGateway("knox.example.com");
+  }
+
+  @Test
+  public void testAddSelfSignedCertForGatewayCalculateHostname() throws Exception {
+    testAddSelfSignedCertForGateway("hostname");
+  }
+
+  @Test
+  public void testGetKeyAndCertificateForGateway() throws Exception {
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    replay(masterService);
+
+    Path baseDir = testFolder.newFolder().toPath();
+    GatewayConfigImpl config = createGatewayConfig(baseDir);
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.setMasterService(masterService);
+    keystoreService.init(config, Collections.emptyMap());
+
+    createKeystore(keystoreService, Paths.get(config.getIdentityKeystorePath()), config.getIdentityKeyAlias(), masterPassword);
+
+    assertNull(keystoreService.getKeyForGateway("wrongpassword".toCharArray()));
+    assertNotNull(keystoreService.getKeyForGateway(masterPassword));
+    assertNotNull(keystoreService.getKeyForGateway(null)); // implicitly should use master secret
+
+    assertNotNull(keystoreService.getCertificateForGateway());
+
+    verify(masterService);
+  }
+
+  @Test
+  public void testAddRemoveCredentialForCluster() throws Exception {
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    replay(masterService);
+
+    Path baseDir = testFolder.newFolder().toPath();
+    GatewayConfigImpl config = createGatewayConfig(baseDir);
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.setMasterService(masterService);
+    keystoreService.init(config, Collections.emptyMap());
+
+
+    String notClusterName = "cluster_not";
+    String notAlias= "alias_not";
+    String clusterName = "cluster";
+    String alias = "alias1";
+    String value = "value1";
+
+    keystoreService.createCredentialStoreForCluster(clusterName);
+
+    assertNull(keystoreService.getCredentialForCluster(clusterName, alias));
+    assertNull(keystoreService.getCredentialForCluster(notClusterName, alias));
+
+    keystoreService.addCredentialForCluster(clusterName, alias, value);
+    assertEquals(value, String.valueOf(keystoreService.getCredentialForCluster(clusterName, alias)));
+    assertNull(keystoreService.getCredentialForCluster(notClusterName, alias));
+    assertNull(keystoreService.getCredentialForCluster(clusterName, notAlias));
+    assertNull(keystoreService.getCredentialForCluster(notClusterName, notAlias));
+
+    keystoreService.removeCredentialForCluster(clusterName, alias);
+    assertNull(keystoreService.getCredentialForCluster(clusterName, alias));
+
+    verify(masterService);
+  }
+
+  private void testAddSelfSignedCertForGateway(String hostname) throws Exception {
+    char[] masterPassword = "master_password".toCharArray();
+
+    MasterService masterService = createMock(MasterService.class);
+    expect(masterService.getMasterSecret()).andReturn(masterPassword).anyTimes();
+
+    replay(masterService);
+
+    Path baseFolder = testFolder.newFolder().toPath();
+    GatewayConfig config = createGatewayConfig(baseFolder);
+
+    Path defaultFile = baseFolder.resolve("security").resolve("keystores").resolve("gateway.jks");
+
+    DefaultKeystoreService keystoreService = new DefaultKeystoreService();
+    keystoreService.init(config, Collections.emptyMap());
+    keystoreService.setMasterService(masterService);
+
+    keystoreService.createKeyStore(defaultFile, "JKS", masterPassword);
+
+    String alias;
+    char[] password;
+    String expectedSubjectName;
+    if (hostname == null) {
+      alias = "test_localhost";
+      password = "test_localhost".toCharArray();
+      expectedSubjectName = "CN=localhost, OU=Test, O=Hadoop, L=Test, ST=Test, C=US";
+
+      keystoreService.addSelfSignedCertForGateway(alias, password);
+    } else {
+      alias = "test_" + hostname;
+      password = ("test_" + hostname).toCharArray();
+
+      if ("hostname".equals(hostname)) {
+        expectedSubjectName = "CN=" + InetAddress.getLocalHost().getHostName() + ", OU=Test, O=Hadoop, L=Test, ST=Test, C=US";
+      } else {
+        expectedSubjectName = "CN=" + hostname + ", OU=Test, O=Hadoop, L=Test, ST=Test, C=US";
+      }
+
+      keystoreService.addSelfSignedCertForGateway(alias, password, hostname);
+    }
+
+    assertNotNull(keystoreService.getKeyForGateway(alias, password));
+
+    KeyStore keystore = keystoreService.getKeystoreForGateway();
+    assertNotNull(keystore);
+    assertNotNull(keystore.getKey(alias, password));
+
+    Certificate certificate = keystore.getCertificate(alias);
+    assertTrue(certificate instanceof X509Certificate);
+
+    Principal subject = ((X509Certificate) certificate).getSubjectDN();
+    assertEquals(expectedSubjectName, subject.getName());
+
+    verify(masterService);
+  }
+
+  private void testCreateGetAndCheckKeystoreForGateway(KeystoreService keystoreService,
+                                                       Path expectedKeystoreFilePath,
+                                                       String expectedAlias,
+                                                       char[] keyPassword,
+                                                       GatewayConfig config) throws Exception {
+    assertEquals(expectedKeystoreFilePath.toAbsolutePath().toString(), keystoreService.getKeystorePath());
+    assertFalse(Files.exists(expectedKeystoreFilePath));
+
+    assertFalse(keystoreService.isKeystoreForGatewayAvailable());
+
+    keystoreService.createKeystoreForGateway();
+    // The keystore file has now been created
+    assertTrue(Files.exists(expectedKeystoreFilePath));
+    KeyStore postCreateKeystore = keystoreService.getKeystoreForGateway();
+    assertNotNull(postCreateKeystore);
+    assertEquals(0, postCreateKeystore.size());
+
+    keystoreService.addSelfSignedCertForGateway(config.getIdentityKeyAlias(), keyPassword, "localhost");
+    assertNotNull(keystoreService.getKeyForGateway(expectedAlias, keyPassword));
+
+    assertEquals(0, postCreateKeystore.size());
+    // reread the keystore
+    postCreateKeystore = keystoreService.getKeystoreForGateway();
+    assertEquals(1, postCreateKeystore.size());
+
+    assertNotNull(postCreateKeystore.getKey(expectedAlias, keyPassword));
+    Certificate certificate = postCreateKeystore.getCertificate(expectedAlias);
+    assertNotNull(certificate);
+  }
+
+  private void testSigningKeystore(KeystoreService keystoreService,
+                                   Path expectedKeystoreFilePath,
+                                   String keyAlias,
+                                   char[] masterPassword) throws Exception {
+    assertTrue(Files.exists(expectedKeystoreFilePath));
+    assertNotNull(keystoreService.getSigningKeystore());
+    assertNotNull(keystoreService.getSigningKey(keyAlias, masterPassword));
+  }
+
+  private GatewayConfigImpl createGatewayConfig(Path baseDir) {
+    GatewayConfigImpl config = new GatewayConfigImpl();
+    config.set("gateway.data.dir", baseDir.toAbsolutePath().toString());
+    config.set("gateway.security.dir", baseDir.resolve("security").toAbsolutePath().toString());
+    return config;
+
+  }
+
+  private void createKeystore(DefaultKeystoreService keystoreService, Path keystoreFilePath, String alias, char[] password)
+      throws KeystoreServiceException, KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
+    KeyStore keystore = keystoreService.createKeyStore(keystoreFilePath, "JKS", password);
+
+    KeyPairGenerator keyPairGenerator;
+    keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+    keyPairGenerator.initialize(2048);
+    KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+    X509Certificate cert = X509CertificateUtil.generateCertificate(
+        String.format(Locale.ROOT, "CN=%s,OU=Test,O=Hadoop,L=Test,ST=Test,C=US", this.getClass().getName()),
+        keyPair,
+        365,
+        "SHA1withRSA");
+
+    keystore.setKeyEntry(alias, keyPair.getPrivate(),
+        password,
+        new java.security.cert.Certificate[]{cert});
+
+    keystoreService.writeKeyStoreToFile(keystore, keystoreFilePath, password);
+  }
 }
\ No newline at end of file
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/i18n/GatewaySpiMessages.java b/gateway-spi/src/main/java/org/apache/knox/gateway/i18n/GatewaySpiMessages.java
index 589e24d..2a5389b 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/i18n/GatewaySpiMessages.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/i18n/GatewaySpiMessages.java
@@ -37,21 +37,6 @@ public interface GatewaySpiMessages {
   @Message( level = MessageLevel.ERROR, text = "Failed to generate secret key from password: {0}" )
   void failedToGenerateKeyFromPassword( @StackTrace( level = MessageLevel.DEBUG ) Exception e );
 
-  @Message( level = MessageLevel.ERROR, text = "Failed to create keystore [filename={0}, type={1}]: {2}" )
-  void failedToCreateKeystore( String fileName, String keyStoreType, @StackTrace( level = MessageLevel.DEBUG ) Exception e );
-
-  @Message( level = MessageLevel.ERROR, text = "Failed to load keystore [filename={0}, type={1}]: {2}" )
-  void failedToLoadKeystore( String fileName, String keyStoreType, @StackTrace( level = MessageLevel.DEBUG ) Exception e );
-
-  @Message( level = MessageLevel.ERROR, text = "Failed to add credential: {1}" )
-  void failedToAddCredential( @StackTrace( level = MessageLevel.DEBUG ) Exception e );
-
-  @Message(level = MessageLevel.ERROR, text = "Failed to remove credential: {1}")
-  void failedToRemoveCredential(@StackTrace(level = MessageLevel.DEBUG) Exception e);
-
-  @Message( level = MessageLevel.ERROR, text = "Failed to get credential: {1}" )
-  void failedToGetCredential(@StackTrace( level = MessageLevel.DEBUG ) Exception e);
-
   @Message( level = MessageLevel.ERROR, text = "Failed to persist master secret: {0}" )
   void failedToPersistMasterSecret( @StackTrace( level = MessageLevel.DEBUG ) Exception e );
 
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/BaseKeystoreService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/BaseKeystoreService.java
deleted file mode 100644
index ffa5759..0000000
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/BaseKeystoreService.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.knox.gateway.services.security.impl;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.knox.gateway.i18n.GatewaySpiMessages;
-import org.apache.knox.gateway.i18n.messages.MessagesFactory;
-import org.apache.knox.gateway.services.security.KeystoreServiceException;
-import org.apache.knox.gateway.services.security.MasterService;
-
-import javax.crypto.spec.SecretKeySpec;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-
-public class BaseKeystoreService {
-  private static GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
-
-  protected MasterService masterService;
-  protected String keyStoreDir;
-
-  private static KeyStore loadKeyStore(final File keyStoreFile, final char[] masterPassword, String storeType)
-      throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException {
-       final KeyStore  keyStore = KeyStore.getInstance(storeType);
-       if ( keyStoreFile.exists() ) {
-           try (InputStream input = Files.newInputStream(keyStoreFile.toPath())) {
-               keyStore.load( input, masterPassword );
-           }
-       } else {
-           keyStore.load( null, masterPassword );
-       }
-
-       return keyStore;
-      }
-
-  private static OutputStream createKeyStoreFile(String fileName ) throws IOException {
-    File file = new File( fileName );
-    if( file.exists() ) {
-      if( file.isDirectory() ) {
-        throw new IOException( file.getAbsolutePath() );
-      } else if( !file.canWrite() ) {
-        throw new IOException( file.getAbsolutePath() );
-      }
-    } else {
-      File dir = file.getParentFile();
-      if( !dir.exists() ) {
-        if( !dir.mkdirs() ) {
-          throw new IOException( file.getAbsolutePath() );
-        }
-      }
-    }
-    return Files.newOutputStream( file.toPath() );
-  }
-
-  protected void createKeystore(String filename, String keystoreType, char[] password) throws KeystoreServiceException {
-    try (OutputStream out = createKeyStoreFile( filename )) {
-      KeyStore ks = KeyStore.getInstance(keystoreType);
-      ks.load( null, null );
-      ks.store( out, password );
-    } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) {
-      LOG.failedToCreateKeystore( filename, keystoreType, e );
-      throw new KeystoreServiceException(e);
-    }
-  }
-
-  protected boolean isKeystoreAvailable(final File keyStoreFile, String storeType, char[] password) throws KeyStoreException, IOException {
-    if ( keyStoreFile.exists() ) {
-      try (InputStream input = Files.newInputStream(keyStoreFile.toPath())){
-        final KeyStore keyStore = KeyStore.getInstance(storeType);
-        keyStore.load( input, password );
-        return true;
-      } catch (NoSuchAlgorithmException | CertificateException e) {
-        LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e );
-      } catch (IOException | KeyStoreException e) {
-        LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e );
-        throw e;
-      }
-    }
-    return false;
-  }
-
-  protected KeyStore getKeystore(final File keyStoreFile, String storeType, char[] password) throws KeystoreServiceException {
-    KeyStore credStore;
-    try {
-      credStore = loadKeyStore( keyStoreFile, password, storeType);
-    } catch (CertificateException | IOException | NoSuchAlgorithmException | KeyStoreException e) {
-      LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e );
-      throw new KeystoreServiceException(e);
-    }
-    return credStore;
-  }
-
-  public BaseKeystoreService() {
-    super();
-  }
-
-  protected void addCredential(String alias, String value, KeyStore ks) {
-    if (ks != null) {
-      try {
-        final Key key = new SecretKeySpec(value.getBytes(StandardCharsets.UTF_8), "AES");
-        ks.setKeyEntry( alias, key, masterService.getMasterSecret(), null);
-      } catch (KeyStoreException e) {
-        LOG.failedToAddCredential(e);
-      }
-    }
-  }
-
-  public void removeCredential(String alias, KeyStore ks) {
-    if (ks != null) {
-      try {
-        if (ks.containsAlias(alias)) {
-          ks.deleteEntry(alias);
-        }
-      } catch (KeyStoreException e) {
-        LOG.failedToRemoveCredential(e);
-      }
-    }
-  }
-
-  protected char[] getCredential(String alias, char[] credential, KeyStore ks) {
-    if (ks != null) {
-      try {
-        credential = new String(ks.getKey(alias, masterService.getMasterSecret()).getEncoded(), StandardCharsets.UTF_8).toCharArray();
-      } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) {
-        LOG.failedToGetCredential(e);
-      }
-    }
-    return credential;
-  }
-
-  protected void writeCertificateToFile( Certificate cert, final File file ) throws CertificateEncodingException, IOException {
-    byte[] bytes = cert.getEncoded();
-    Base64 encoder = new Base64( 76, "\n".getBytes( StandardCharsets.US_ASCII ) );
-    try( OutputStream out = Files.newOutputStream( file.toPath() ) ) {
-      out.write( "-----BEGIN CERTIFICATE-----\n".getBytes( StandardCharsets.US_ASCII ) );
-      out.write( encoder.encodeToString( bytes ).getBytes( StandardCharsets.US_ASCII ) );
-      out.write( "-----END CERTIFICATE-----\n".getBytes( StandardCharsets.US_ASCII ) );
-    }
-  }
-
-  protected void writeKeystoreToFile(final KeyStore keyStore, final File file, char[] password)
-      throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
-     // TODO: backup the keystore on disk before attempting a write and restore on failure
-     try( OutputStream out = Files.newOutputStream(file.toPath()) ) {
-         keyStore.store( out, password );
-     }
-  }
-
-  public void setMasterService(MasterService ms) {
-    this.masterService = ms;
-  }
-}
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreService.java
deleted file mode 100644
index 205db12..0000000
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreService.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.knox.gateway.services.security.impl;
-
-import java.io.File;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import org.apache.knox.gateway.i18n.GatewaySpiMessages;
-import org.apache.knox.gateway.i18n.messages.MessagesFactory;
-import org.apache.knox.gateway.services.ServiceLifecycleException;
-import org.apache.knox.gateway.services.security.KeystoreServiceException;
-import org.apache.knox.gateway.util.X509CertificateUtil;
-
-public class CMFKeystoreService extends BaseKeystoreService {
-  private static GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
-
-  private static final String TEST_CERT_DN = "CN=hadoop,OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
-  private static final String CREDENTIALS_SUFFIX = "-credentials.jceks";
-
-  private String serviceName;
-
-  public CMFKeystoreService(String keystoreDir, String serviceName)
-      throws ServiceLifecycleException {
-    this.serviceName = serviceName;
-    this.keyStoreDir = keystoreDir + File.separator;
-    File ksd = new File(this.keyStoreDir);
-    if (!ksd.exists() && !ksd.mkdirs()) {
-      throw new ServiceLifecycleException("Cannot create the keystore directory");
-    }
-  }
-
-  public void createKeystore() throws KeystoreServiceException {
-    String filename = keyStoreDir + serviceName + ".jks";
-    createKeystore(filename, "JKS", masterService.getMasterSecret());
-  }
-
-  public KeyStore getKeystore() throws KeystoreServiceException {
-    final File  keyStoreFile = new File( keyStoreDir + serviceName  );
-    return getKeystore(keyStoreFile, "JKS", masterService.getMasterSecret());
-  }
-
-  public void addSelfSignedCert(String alias, char[] passphrase)
-      throws KeystoreServiceException {
-    KeyPairGenerator keyPairGenerator;
-    try {
-      keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-      keyPairGenerator.initialize(2048);
-      KeyPair KPair = keyPairGenerator.generateKeyPair();
-      X509Certificate cert = X509CertificateUtil.generateCertificate(TEST_CERT_DN, KPair, 365, "SHA1withRSA");
-
-      KeyStore privateKS = getKeystore();
-      if (privateKS != null) {
-        privateKS.setKeyEntry(alias, KPair.getPrivate(),
-          passphrase,
-          new java.security.cert.Certificate[]{cert});
-        writeKeystoreToFile(privateKS, new File( keyStoreDir + serviceName  ), masterService.getMasterSecret());
-      } else {
-        throw new IOException("Unable to open gateway keystore.");
-      }
-    } catch (IOException | GeneralSecurityException e) {
-      LOG.failedToAddSeflSignedCertForGateway(alias, e);
-    }
-  }
-
-  public void createCredentialStore() throws KeystoreServiceException {
-    String filename = keyStoreDir + serviceName + CREDENTIALS_SUFFIX;
-    createKeystore(filename, "JCEKS", masterService.getMasterSecret());
-  }
-
-  public boolean isCredentialStoreAvailable() throws KeystoreServiceException {
-    final File  keyStoreFile = new File( keyStoreDir + serviceName + CREDENTIALS_SUFFIX  );
-    try {
-      return isKeystoreAvailable(keyStoreFile, "JCEKS", masterService.getMasterSecret());
-    } catch (KeyStoreException | IOException e) {
-      throw new KeystoreServiceException(e);
-    }
-  }
-
-  public boolean isKeystoreAvailable() throws KeystoreServiceException {
-    final File  keyStoreFile = new File( keyStoreDir + serviceName + ".jks" );
-    try {
-      return isKeystoreAvailable(keyStoreFile, "JKS", masterService.getMasterSecret());
-    } catch (KeyStoreException | IOException e) {
-      throw new KeystoreServiceException(e);
-    }
-  }
-
-  public Key getKey(String alias, char[] passphrase) throws KeystoreServiceException {
-    Key key = null;
-    KeyStore ks = getKeystore();
-    if (ks != null) {
-      try {
-        key = ks.getKey(alias, passphrase);
-      } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
-        LOG.failedToGetKey(alias, e);
-      }
-    }
-    return key;
-  }
-
-  public KeyStore getCredentialStore() throws KeystoreServiceException {
-    final File  keyStoreFile = new File( keyStoreDir + serviceName + CREDENTIALS_SUFFIX  );
-    return getKeystore(keyStoreFile, "JCEKS", masterService.getMasterSecret());
-  }
-
-  public void addCredential(String alias, String value) throws KeystoreServiceException {
-    KeyStore ks = getCredentialStore();
-    addCredential(alias, value, ks);
-    final File  keyStoreFile = new File( keyStoreDir + serviceName + CREDENTIALS_SUFFIX  );
-    try {
-      writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
-    } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
-      LOG.failedToAddCredential(e);
-    }
-  }
-
-  public char[] getCredential(String alias) throws KeystoreServiceException {
-    char[] credential = null;
-    KeyStore ks = getCredentialStore();
-    credential = getCredential(alias, credential, ks);
-    return credential;
-  }
-
-}
diff --git a/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreServiceTest.java b/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreServiceTest.java
deleted file mode 100644
index 8a21782..0000000
--- a/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/impl/CMFKeystoreServiceTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.knox.gateway.services.security.impl;
-
-import java.io.File;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.util.Map;
-
-import org.apache.knox.gateway.config.GatewayConfig;
-import org.apache.knox.gateway.services.ServiceLifecycleException;
-import org.apache.knox.gateway.services.security.KeystoreServiceException;
-import org.apache.knox.gateway.services.security.MasterService;
-import org.apache.knox.test.category.FastTests;
-import org.apache.knox.test.category.UnitTests;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
-*
-*/
-@Category( { UnitTests.class, FastTests.class } )
-public class CMFKeystoreServiceTest {
-  CMFKeystoreService ks;
-  String aliasName = "TestAliasName";
-  String secretValue = "AliasSecretValue";
-  char[] password = { 'P', 'A', 'S', 'S' };
-  File credentialsStoreFile = new File("ambari-credentials.jceks");
-  File keyStoreFile = new File("ambari.jks");
-  File certificateFile = new File("ambari");
-
-  @Before
-  public void setUp() {
-    try {
-      ks = new CMFKeystoreService(".", "ambari");
-      ks.setMasterService(new MasterService() {
-
-        public void init(GatewayConfig config, Map<String, String> options)
-            throws ServiceLifecycleException {
-        }
-
-        public void start() throws ServiceLifecycleException {}
-
-        public void stop() throws ServiceLifecycleException {}
-
-        @Override
-        public char[] getMasterSecret() {
-          return "testmaster".toCharArray();
-        }
-
-      });
-    } catch (ServiceLifecycleException e) {
-      e.printStackTrace();
-    }
-  }
-
-  @Test
-  public void testCreationOfStoreForCredential() throws KeystoreServiceException {
-    try {
-      ks.createCredentialStore();
-      assertTrue("Credential Store file is not created", ks.isCredentialStoreAvailable()
-          && credentialsStoreFile.exists());
-      KeyStore credentialStore = ks.getCredentialStore();
-      assertTrue("Credential Store file is not created with proper file type",
-        ("JCEKS").equalsIgnoreCase(credentialStore.getType()));
-    } finally {
-      credentialsStoreFile.deleteOnExit();
-    }
-  }
-
-  @Test
-  public void testCreationOfKeyStore() throws KeystoreServiceException {
-    try {
-      ks.createKeystore();
-      assertTrue("Key Store file is not created", ks.isKeystoreAvailable() && keyStoreFile.exists());
-      KeyStore keystore = ks.getKeystore();
-      assertTrue("Key Store file is not created with proper file type",
-        ("JKS").equalsIgnoreCase(keystore.getType()));
-      ks.createCredentialStore();
-      ks.addCredential(aliasName, "secretValue");
-    } finally {
-      keyStoreFile.deleteOnExit();
-      credentialsStoreFile.deleteOnExit();
-    }
-  }
-
-  @Test
-  public void testAdditionOfCredentialsToKeyStore() throws KeystoreServiceException {
-    try {
-      ks.createKeystore();
-      ks.createCredentialStore();
-      ks.addCredential(aliasName, "secretValue");
-      char[] secret = ks.getCredential(aliasName);
-      assertEquals("Addition of Credentials failed", "secretValue", new String(secret));
-    } finally {
-      credentialsStoreFile.deleteOnExit();
-      keyStoreFile.deleteOnExit();
-    }
-  }
-
-  @Test
-  public void testAdditionOfAliasWithSelfSignedCertificate() throws KeystoreServiceException,
-      KeyStoreException {
-    try {
-      ks.createKeystore();
-      ks.createCredentialStore();
-      ks.addCredential(aliasName, "secretValue");
-      ks.addSelfSignedCert(aliasName, password);
-      KeyStore keystore = ks.getKeystore();
-      assertTrue("Addition of Alias with Self Signed Certificate failed",
-        !keystore.getCertificate(aliasName).toString().isEmpty() && certificateFile.exists());
-    } finally {
-      credentialsStoreFile.deleteOnExit();
-      keyStoreFile.deleteOnExit();
-      certificateFile.deleteOnExit();
-    }
-  }
-
-  @Test
-  public void testFetchOfAliasKey() throws KeystoreServiceException {
-    try {
-      ks.createKeystore();
-      ks.createCredentialStore();
-      ks.addCredential(aliasName, "secretValue");
-      ks.addSelfSignedCert(aliasName, password);
-      assertTrue("Fetch of AliasKey failed", !ks.getKey(aliasName, password).toString().isEmpty()
-          && certificateFile.exists());
-    } finally {
-      credentialsStoreFile.deleteOnExit();
-      keyStoreFile.deleteOnExit();
-      certificateFile.deleteOnExit();
-    }
-  }
-}


Mime
View raw message