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 4576656 KNOX-1756 - Knox Gateway TLS Keystore and Alias Should be
Configurable (#56)
4576656 is described below
commit 45766567d15ec814e6379dcce9e93043a0ffef91
Author: Robert Levas <[email protected]>
AuthorDate: Mon Feb 25 10:29:07 2019 -0500
KNOX-1756 - Knox Gateway TLS Keystore and Alias Should be Configurable (#56)
---
.../apache/knox/gateway/pac4j/Pac4jMessages.java | 6 +-
.../pac4j/filter/Pac4jDispatcherFilter.java | 25 +++--
.../org/apache/knox/gateway/GatewayServer.java | 3 +-
.../gateway/config/impl/GatewayConfigImpl.java | 77 ++++++++++++-
.../gateway/services/DefaultGatewayServices.java | 16 +--
.../impl/DefaultServiceRegistryService.java | 4 +-
.../security/impl/DefaultAliasService.java | 45 +++++++-
.../security/impl/DefaultCryptoService.java | 10 +-
.../security/impl/DefaultKeystoreService.java | 79 +++++++++-----
.../services/security/impl/JettySSLService.java | 31 ++++--
.../services/security/impl/RemoteAliasService.java | 42 +++++++-
.../token/impl/DefaultTokenAuthorityService.java | 12 +--
.../java/org/apache/knox/gateway/util/KnoxCLI.java | 111 +++++++++++++++----
.../gateway/config/impl/GatewayConfigImplTest.java | 55 ++++++++++
.../services/security/CryptoServiceTest.java | 15 +++
.../impl/DefaultTokenAuthorityServiceTest.java | 66 ++++++++----
.../apache/knox/gateway/websockets/BadUrlTest.java | 77 ++++++++++++-
.../knox/gateway/websockets/WebsocketEchoTest.java | 76 ++++++++++++-
.../WebsocketMultipleConnectionTest.java | 76 ++++++++++++-
.../gateway/service/knoxtoken/TokenResource.java | 4 +-
.../apache/knox/gateway/config/GatewayConfig.java | 100 +++++++++++++++++
.../gateway/services/security/AliasService.java | 6 ++
.../gateway/services/security/CryptoService.java | 4 +-
.../gateway/services/security/KeystoreService.java | 6 ++
.../knox/gateway/services/security/SSLService.java | 2 +-
.../security/impl/BaseKeystoreService.java | 16 +--
.../services/security/impl/CMFKeystoreService.java | 16 +--
.../security/impl/X509CertificateUtil.java | 16 +++
.../org/apache/knox/gateway/GatewayTestConfig.java | 119 ++++++++++++++++++---
29 files changed, 952 insertions(+), 163 deletions(-)
diff --git
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/Pac4jMessages.java
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/Pac4jMessages.java
index 56840c0..250d7be 100644
---
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/Pac4jMessages.java
+++
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/Pac4jMessages.java
@@ -45,6 +45,10 @@ public interface Pac4jMessages {
void unableToGenerateAPasswordForEncryption(Exception e);
@Message( level = MessageLevel.INFO, text =
- "No private key passphrase alias found. Defaulting to master. Exception
encountered: {0}")
+ "No private key passphrase alias found. Defaulting to master secret.
Exception encountered: {0}")
void noPrivateKeyPasshraseProvisioned(Exception e);
+
+ @Message( level = MessageLevel.ERROR, text =
+ "No keystore password alias found. Defaulting to master secret.
Exception encountered: {0}")
+ void noKeystorePasswordProvisioned(Exception e);
}
diff --git
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
index 6393672..b220718 100644
---
a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
+++
b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
@@ -223,8 +223,19 @@ public class Pac4jDispatcherFilter implements Filter {
properties.put(PropertiesConfigFactory.SAML_KEYSTORE_PATH,
keystoreService.getKeystorePath());
- properties.put(PropertiesConfigFactory.SAML_KEYSTORE_PASSWORD,
- new String(masterService.getMasterSecret()));
+ // check for provisioned alias for keystore password
+ char[] giksp = null;
+ try {
+ giksp = aliasService.getGatewayIdentityKeystorePassword();
+ } catch (AliasServiceException e) {
+ log.noKeystorePasswordProvisioned(e);
+ }
+ if (giksp == null) {
+ // no alias provisioned then use the master
+ giksp = masterService.getMasterSecret();
+ }
+ properties.put(PropertiesConfigFactory.SAML_KEYSTORE_PASSWORD, new
String(giksp));
+
// check for provisioned alias for private key
char[] gip = null;
try {
@@ -233,15 +244,11 @@ public class Pac4jDispatcherFilter implements Filter {
catch(AliasServiceException ase) {
log.noPrivateKeyPasshraseProvisioned(ase);
}
- if (gip != null) {
- properties.put(PropertiesConfigFactory.SAML_PRIVATE_KEY_PASSWORD,
- new String(gip));
- }
- else {
+ if (gip == null) {
// no alias provisioned then use the master
- properties.put(PropertiesConfigFactory.SAML_PRIVATE_KEY_PASSWORD,
- new String(masterService.getMasterSecret()));
+ gip = masterService.getMasterSecret();
}
+ properties.put(PropertiesConfigFactory.SAML_PRIVATE_KEY_PASSWORD, new
String(gip));
}
}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index a935933..b5f6aa6 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -370,8 +370,7 @@ public class GatewayServer {
httpsConfig.setSecurePort( connectorPort );
httpsConfig.addCustomizer( new SecureRequestCustomizer() );
SSLService ssl = services.getService("SSLService");
- String keystoreFileName = config.getGatewaySecurityDir() +
File.separatorChar + "keystores" + File.separatorChar + "gateway.jks";
- SslContextFactory sslContextFactory =
(SslContextFactory)ssl.buildSslContextFactory( keystoreFileName );
+ SslContextFactory sslContextFactory =
(SslContextFactory)ssl.buildSslContextFactory(
config.getIdentityKeystorePath(), config.getIdentityKeystoreType(),
config.getIdentityKeyAlias() );
connector = new ServerConnector( server, sslContextFactory, new
HttpConnectionFactory( httpsConfig ) );
} else {
connector = new ServerConnector( server );
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 5060831..cedf6cf 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -33,6 +33,7 @@ import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -427,6 +428,11 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
}
@Override
+ public String getGatewayKeystoreDir() {
+ return Paths.get(getGatewaySecurityDir(),
"keystores").toAbsolutePath().toString();
+ }
+
+ @Override
public InetSocketAddress getGatewayAddress() throws UnknownHostException {
String host = getGatewayHost();
int port = getGatewayPort();
@@ -644,13 +650,82 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
}
@Override
+ public String getIdentityKeystorePath() {
+ String keystorePath = get(IDENTITY_KEYSTORE_PATH);
+ if(StringUtils.isEmpty(keystorePath)) {
+ keystorePath = Paths.get(getGatewayKeystoreDir(),
DEFAULT_GATEWAY_KEYSTORE_NAME).toAbsolutePath().toString();
+ }
+ return keystorePath;
+ }
+
+ @Override
+ public String getIdentityKeystoreType() {
+ return get(IDENTITY_KEYSTORE_TYPE, DEFAULT_IDENTITY_KEYSTORE_TYPE);
+ }
+
+ @Override
+ public String getIdentityKeystorePasswordAlias() {
+ return get(IDENTITY_KEYSTORE_PASSWORD_ALIAS,
DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS);
+ }
+
+ @Override
+ public String getIdentityKeyAlias() {
+ return get(IDENTITY_KEY_ALIAS, DEFAULT_IDENTITY_KEY_ALIAS);
+ }
+
+ @Override
+ public String getIdentityKeyPassphraseAlias() {
+ return get(IDENTITY_KEY_PASSPHRASE_ALIAS,
DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS);
+ }
+
+ @Override
public String getSigningKeystoreName() {
return get(SIGNING_KEYSTORE_NAME);
}
@Override
+ public String getSigningKeystorePath() {
+ if (getSigningKeystoreName() == null) {
+ return getIdentityKeystorePath();
+ } else {
+ return Paths.get(getGatewayKeystoreDir(),
getSigningKeystoreName()).toAbsolutePath().toString();
+ }
+ }
+
+ @Override
+ public String getSigningKeystoreType() {
+ if (getSigningKeystoreName() == null) {
+ return getIdentityKeystoreType();
+ } else {
+ return get(SIGNING_KEYSTORE_TYPE, DEFAULT_SIGNING_KEYSTORE_TYPE);
+ }
+ }
+
+ @Override
public String getSigningKeyAlias() {
- return get(SIGNING_KEY_ALIAS);
+ if (getSigningKeystoreName() == null) {
+ return getIdentityKeyAlias();
+ } else {
+ return get(SIGNING_KEY_ALIAS, DEFAULT_SIGNING_KEY_ALIAS);
+ }
+ }
+
+ @Override
+ public String getSigningKeystorePasswordAlias() {
+ if (getSigningKeystoreName() == null) {
+ return getIdentityKeystorePasswordAlias();
+ } else {
+ return get(SIGNING_KEYSTORE_PASSWORD_ALIAS,
DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS);
+ }
+ }
+
+ @Override
+ public String getSigningKeyPassphraseAlias() {
+ if (getSigningKeystoreName() == null) {
+ return getIdentityKeyPassphraseAlias();
+ } else {
+ return get(SIGNING_KEY_PASSPHRASE_ALIAS,
DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS);
+ }
}
@Override
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
index 52ff41b..d9c5a73 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/DefaultGatewayServices.java
@@ -101,13 +101,6 @@ public class DefaultGatewayServices implements
GatewayServices {
crypto.init(config, options);
services.put(CRYPTO_SERVICE, crypto);
- DefaultTokenAuthorityService ts = new DefaultTokenAuthorityService();
- ts.setAliasService(alias);
- ts.setKeystoreService(ks);
- ts.init(config, options);
- // prolly should not allow the token service to be looked up?
- services.put(TOKEN_SERVICE, ts);
-
JettySSLService ssl = new JettySSLService();
ssl.setAliasService(alias);
ssl.setKeystoreService(ks);
@@ -115,6 +108,15 @@ public class DefaultGatewayServices implements
GatewayServices {
ssl.init(config, options);
services.put(SSL_SERVICE, ssl);
+ // The DefaultTokenAuthorityService needs to be initialized after the
JettySSLService to ensure
+ // that the signing keystore is available for it.
+ DefaultTokenAuthorityService ts = new DefaultTokenAuthorityService();
+ ts.setAliasService(alias);
+ ts.setKeystoreService(ks);
+ ts.init(config, options);
+ // prolly should not allow the token service to be looked up?
+ services.put(TOKEN_SERVICE, ts);
+
DefaultServiceRegistryService sr = new DefaultServiceRegistryService();
sr.setCryptoService( crypto );
sr.init( config, options );
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceRegistryService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceRegistryService.java
index 34f1697..124c9d9 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceRegistryService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceRegistryService.java
@@ -63,7 +63,7 @@ public class DefaultServiceRegistryService implements
ServiceRegistry, Service {
@Override
public String getRegistrationCode(String clusterName) {
String code = generateRegCode(16);
- byte[] signature = crypto.sign("SHA256withRSA","gateway-identity",code);
+ byte[] signature = crypto.sign("SHA256withRSA", code);
String encodedSig = Base64.encodeBase64URLSafeString(signature);
return code + "::" + encodedSig;
@@ -93,7 +93,7 @@ public class DefaultServiceRegistryService implements
ServiceRegistry, Service {
String[] parts = regCode.split("::");
// part one is the code and part two is the signature
- boolean verified = crypto.verify("SHA256withRSA", "gateway-identity",
parts[0], Base64.decodeBase64(parts[1]));
+ boolean verified = crypto.verify("SHA256withRSA", parts[0],
Base64.decodeBase64(parts[1]));
if (verified) {
Map<String,RegEntry> clusterServices = registry.get(clusterName);
if (clusterServices == null) {
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultAliasService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultAliasService.java
index bddfb88..2f0dae5 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultAliasService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultAliasService.java
@@ -39,14 +39,14 @@ import org.apache.knox.gateway.util.PasswordUtils;
public class DefaultAliasService implements AliasService {
private static final GatewayMessages LOG = MessagesFactory.get(
GatewayMessages.class );
- private static final String GATEWAY_IDENTITY_PASSPHRASE =
"gateway-identity-passphrase";
-
private KeystoreService keystoreService;
private MasterService masterService;
+ private GatewayConfig config;
@Override
public void init(GatewayConfig config, Map<String, String> options)
throws ServiceLifecycleException {
+ this.config = config;
}
@Override
@@ -59,8 +59,47 @@ public class DefaultAliasService implements AliasService {
@Override
public char[] getGatewayIdentityPassphrase() throws AliasServiceException {
- char[] passphrase =
getPasswordFromAliasForGateway(GATEWAY_IDENTITY_PASSPHRASE);
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
+ if (passphrase == null) {
+ // Fall back to the keystore password if a key-specific password was not
explicitly set.
+ passphrase = getGatewayIdentityKeystorePassword();
+ }
+ if (passphrase == null) {
+ // Use the master password if not password was found
+ passphrase = masterService.getMasterSecret();
+ }
+ return passphrase;
+ }
+
+ @Override
+ public char[] getGatewayIdentityKeystorePassword() throws
AliasServiceException {
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getIdentityKeystorePasswordAlias());
+ if (passphrase == null) {
+ // Use the master password if not password was found
+ passphrase = masterService.getMasterSecret();
+ }
+ return passphrase;
+ }
+
+ @Override
+ public char[] getSigningKeyPassphrase() throws AliasServiceException {
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
+ if (passphrase == null) {
+ // Fall back to the keystore password if a key-specific password was not
explicitly set.
+ passphrase = getSigningKeystorePassword();
+ }
+ if (passphrase == null) {
+ // Use the master password if not password was found
+ passphrase = masterService.getMasterSecret();
+ }
+ return passphrase;
+ }
+
+ @Override
+ public char[] getSigningKeystorePassword() throws AliasServiceException {
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getSigningKeystorePasswordAlias());
if (passphrase == null) {
+ // Use the master password if not password was found
passphrase = masterService.getMasterSecret();
}
return passphrase;
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java
index 3cf3cb6..3aea783 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultCryptoService.java
@@ -129,14 +129,14 @@ public class DefaultCryptoService implements
CryptoService {
}
@Override
- public boolean verify(String algorithm, String alias, String signed, byte[]
signature) {
+ public boolean verify(String algorithm, String signed, byte[] signature) {
boolean verified = false;
try {
Signature sig=Signature.getInstance(algorithm);
-
sig.initVerify(ks.getKeystoreForGateway().getCertificate(alias).getPublicKey());
+ sig.initVerify(ks.getCertificateForGateway().getPublicKey());
sig.update(signed.getBytes(StandardCharsets.UTF_8));
verified = sig.verify(signature);
- } catch (SignatureException | KeystoreServiceException | KeyStoreException
| InvalidKeyException | NoSuchAlgorithmException e) {
+ } catch (SignatureException | KeystoreServiceException |
InvalidKeyException | NoSuchAlgorithmException | KeyStoreException e) {
LOG.failedToVerifySignature( e );
}
LOG.signatureVerified( verified );
@@ -144,11 +144,11 @@ public class DefaultCryptoService implements
CryptoService {
}
@Override
- public byte[] sign(String algorithm, String alias, String payloadToSign) {
+ public byte[] sign(String algorithm, String payloadToSign) {
try {
char[] passphrase;
passphrase = as.getGatewayIdentityPassphrase();
- PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(alias,
passphrase);
+ PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(passphrase);
Signature signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(payloadToSign.getBytes(StandardCharsets.UTF_8));
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 947b4a8..d62d1ff 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,7 @@
*/
package org.apache.knox.gateway.services.security.impl;
+import org.apache.commons.lang.StringUtils;
import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.GatewayResources;
import org.apache.knox.gateway.config.GatewayConfig;
@@ -31,6 +32,7 @@ import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
@@ -39,6 +41,7 @@ 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.CertificateException;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
@@ -55,13 +58,14 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
private static final String dnTemplate =
"CN={0},OU=Test,O=Hadoop,L=Test,ST=Test,C=US";
private static final String CREDENTIALS_SUFFIX = "-credentials.jceks";
- public static final String GATEWAY_KEYSTORE = "gateway.jks";
+ private static final String NO_CLUSTER_NAME = "__gateway";
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";
private static GatewayMessages LOG = MessagesFactory.get(
GatewayMessages.class );
private static GatewayResources RES = ResourcesFactory.get(
GatewayResources.class );
+ private GatewayConfig config;
private String signingKeystoreName;
private String signingKeyAlias;
private Map<String, Map<String, String>> cache = new ConcurrentHashMap<>();
@@ -75,7 +79,9 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
readLock = lock.readLock();
writeLock = lock.writeLock();
- this.keyStoreDir = config.getGatewaySecurityDir() + File.separator +
"keystores" + File.separator;
+ this.config = config;
+
+ this.keyStoreDir = config.getGatewayKeystoreDir();
File ksd = new File(this.keyStoreDir);
if (!ksd.exists()) {
if( !ksd.mkdirs() ) {
@@ -123,7 +129,7 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
writeLock.lock();
try {
String filename = getKeystorePath();
- createKeystore(filename, "JKS");
+ createKeystore(filename, config.getIdentityKeystoreType(),
getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
} finally {
writeLock.unlock();
}
@@ -131,10 +137,10 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public KeyStore getKeystoreForGateway() throws KeystoreServiceException {
- final File keyStoreFile = new File( keyStoreDir + GATEWAY_KEYSTORE );
+ final File keyStoreFile = new File( config.getIdentityKeystorePath() );
readLock.lock();
try {
- return getKeystore(keyStoreFile, "JKS");
+ return getKeystore(keyStoreFile, config.getIdentityKeystoreType(),
getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
}
finally {
readLock.unlock();
@@ -148,13 +154,17 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public KeyStore getSigningKeystore(String keystoreName) throws
KeystoreServiceException {
- File keyStoreFile;
+ File keyStoreFile;
+ String keyStoreType;
+ char[] password;
if(keystoreName != null) {
- keyStoreFile = new File(keyStoreDir + keystoreName + ".jks");
- } else if (signingKeystoreName != null) {
- keyStoreFile = new File(keyStoreDir + signingKeystoreName);
+ keyStoreFile = new File(keyStoreDir, keystoreName + ".jks");
+ keyStoreType = "jks";
+ password = masterService.getMasterSecret();
} else {
- keyStoreFile = new File(keyStoreDir + GATEWAY_KEYSTORE);
+ keyStoreFile = new File(config.getSigningKeystorePath());
+ keyStoreType = config.getSigningKeystoreType();
+ password = getKeystorePassword(config.getSigningKeystorePasswordAlias());
}
// make sure the keystore exists
@@ -163,7 +173,7 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
}
readLock.lock();
try {
- return getKeystore(keyStoreFile, "JKS");
+ return getKeystore(keyStoreFile, keyStoreType, password);
}
finally {
readLock.unlock();
@@ -209,7 +219,7 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
passphrase,
new java.security.cert.Certificate[]{cert});
- writeKeystoreToFile(privateKS, new File( keyStoreDir +
GATEWAY_KEYSTORE ));
+ writeKeystoreToFile(privateKS, new File(
config.getIdentityKeystorePath() ),
getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
//writeCertificateToFile( cert, new File( keyStoreDir + alias + ".pem"
) );
} catch (GeneralSecurityException | IOException e) {
LOG.failedToAddSeflSignedCertForGateway( alias, e );
@@ -230,10 +240,10 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public void createCredentialStoreForCluster(String clusterName) throws
KeystoreServiceException {
- String filename = keyStoreDir + clusterName + CREDENTIALS_SUFFIX;
+ String filename = Paths.get(keyStoreDir, clusterName +
CREDENTIALS_SUFFIX).toString();
writeLock.lock();
try {
- createKeystore(filename, "JCEKS");
+ createKeystore(filename, "JCEKS", masterService.getMasterSecret());
}
finally {
writeLock.unlock();
@@ -243,11 +253,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 File keyStoreFile = new File( keyStoreDir, clusterName +
CREDENTIALS_SUFFIX );
readLock.lock();
try {
try {
- rc = isKeystoreAvailable(keyStoreFile, "JCEKS");
+ rc = isKeystoreAvailable(keyStoreFile, "JCEKS",
masterService.getMasterSecret());
} catch (KeyStoreException | IOException e) {
throw new KeystoreServiceException(e);
}
@@ -261,11 +271,11 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public boolean isKeystoreForGatewayAvailable() throws
KeystoreServiceException {
boolean rc;
- final File keyStoreFile = new File( keyStoreDir + GATEWAY_KEYSTORE );
+ final File keyStoreFile = new File( config.getIdentityKeystorePath() );
readLock.lock();
try {
try {
- rc = isKeystoreAvailable(keyStoreFile, "JKS");
+ rc = isKeystoreAvailable(keyStoreFile,
config.getIdentityKeystoreType(),
getKeystorePassword(config.getIdentityKeystorePasswordAlias()));
} catch (KeyStoreException | IOException e) {
throw new KeystoreServiceException(e);
}
@@ -301,6 +311,17 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
}
@Override
+ public Key getKeyForGateway(char[] passphrase) throws
KeystoreServiceException {
+ return getKeyForGateway(config.getIdentityKeyAlias(), passphrase);
+ }
+
+ @Override
+ public Certificate getCertificateForGateway() throws
KeystoreServiceException, KeyStoreException {
+ KeyStore ks = getKeystoreForGateway();
+ return (ks == null) ? null :
ks.getCertificate(config.getIdentityKeyAlias());
+ }
+
+ @Override
public Key getSigningKey(String alias, char[] passphrase) throws
KeystoreServiceException {
return getSigningKey(null, alias, passphrase);
}
@@ -332,10 +353,10 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public KeyStore getCredentialStoreForCluster(String clusterName)
throws KeystoreServiceException {
- final File keyStoreFile = new File( keyStoreDir + clusterName +
CREDENTIALS_SUFFIX );
+ final File keyStoreFile = new File( keyStoreDir, clusterName +
CREDENTIALS_SUFFIX );
readLock.lock();
try {
- return getKeystore(keyStoreFile, "JCEKS");
+ return getKeystore(keyStoreFile, "JCEKS",
masterService.getMasterSecret());
}
finally {
readLock.unlock();
@@ -350,9 +371,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 File keyStoreFile = new File( keyStoreDir, clusterName +
CREDENTIALS_SUFFIX );
try {
- writeKeystoreToFile(ks, keyStoreFile);
+ writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
} catch (KeyStoreException | IOException | CertificateException |
NoSuchAlgorithmException e) {
LOG.failedToAddCredentialForCluster( clusterName, e );
}
@@ -395,14 +416,14 @@ 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 File keyStoreFile = new File( keyStoreDir, clusterName +
CREDENTIALS_SUFFIX );
writeLock.lock();
try {
removeFromCache(clusterName, alias);
KeyStore ks = getCredentialStoreForCluster(clusterName);
removeCredential(alias, ks);
try {
- writeKeystoreToFile(ks, keyStoreFile);
+ writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
} catch (KeyStoreException | IOException | CertificateException |
NoSuchAlgorithmException e) {
LOG.failedToRemoveCredentialForCluster(clusterName, e);
}
@@ -450,6 +471,14 @@ public class DefaultKeystoreService extends
BaseKeystoreService implements
@Override
public String getKeystorePath() {
- return keyStoreDir + GATEWAY_KEYSTORE;
+ return config.getIdentityKeystorePath();
+ }
+
+ private char[] getKeystorePassword(String alias) throws
KeystoreServiceException {
+ char[] password = null;
+ if (StringUtils.isNotEmpty(alias)) {
+ password = getCredentialForCluster(NO_CLUSTER_NAME, alias);
+ }
+ return (password == null) ? masterService.getMasterSecret() : password;
}
}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
index b9e5c0c..1e07823 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
@@ -62,7 +62,6 @@ public class JettySSLService implements SSLService {
private boolean clientAuthNeeded;
private boolean trustAllCerts;
private String truststorePath;
- private String keystoreType;
private String trustStoreType;
private boolean clientAuthWanted;
@@ -112,17 +111,16 @@ public class JettySSLService implements SSLService {
if (passphrase == null) {
passphrase = ms.getMasterSecret();
}
- ks.addSelfSignedCertForGateway("gateway-identity", passphrase);
+ ks.addSelfSignedCertForGateway(config.getIdentityKeyAlias(),
passphrase);
}
else {
log.keyStoreForGatewayFoundNotCreating();
}
- logAndValidateCertificate();
+ logAndValidateCertificate(config);
} catch (KeystoreServiceException e) {
- throw new ServiceLifecycleException("Keystore was not loaded properly -
the provided (or persisted) master secret may not match the password for the
keystore.", e);
+ throw new ServiceLifecycleException("The identity keystore was not
loaded properly - the provided password may not match the password for the
keystore.", e);
}
- keystoreType = config.getKeystoreType();
sslIncludeCiphers = config.getIncludedSSLCiphers();
sslExcludeCiphers = config.getExcludedSSLCiphers();
sslExcludeProtocols = config.getExcludedSSLProtocols();
@@ -133,11 +131,11 @@ public class JettySSLService implements SSLService {
trustStoreType = config.getTruststoreType();
}
- private void logAndValidateCertificate() throws ServiceLifecycleException {
+ private void logAndValidateCertificate(GatewayConfig config) throws
ServiceLifecycleException {
// let's log the hostname (CN) and cert expiry from the gateway's public
cert to aid in SSL debugging
Certificate cert;
try {
- cert = as.getCertificateForGateway("gateway-identity");
+ cert = as.getCertificateForGateway(config.getIdentityKeyAlias());
} catch (AliasServiceException e) {
throw new ServiceLifecycleException("Cannot Retreive Gateway SSL
Certificate. Server will not start.", e);
}
@@ -167,13 +165,26 @@ public class JettySSLService implements SSLService {
}
@Override
- public Object buildSslContextFactory(String keystoreFileName ) throws
KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
+ public Object buildSslContextFactory(String keystoreFileName, String
keystoreType, String alias) throws KeyStoreException, IOException,
CertificateException, NoSuchAlgorithmException {
SslContextFactory sslContextFactory = new SslContextFactory( true );
- sslContextFactory.setCertAlias( "gateway-identity" );
+ sslContextFactory.setCertAlias( alias );
sslContextFactory.setKeyStoreType(keystoreType);
sslContextFactory.setKeyStorePath(keystoreFileName);
char[] master = ms.getMasterSecret();
- sslContextFactory.setKeyStorePassword(new String(master));
+
+ char[] keystorePasswordChars = null;
+ try {
+ keystorePasswordChars = as.getGatewayIdentityKeystorePassword();
+ } catch (AliasServiceException e) {
+ log.creatingKeyStoreForGateway();
+ // nop - default passphrase will be used
+ }
+ if(keystorePasswordChars == null) {
+ // If a keystore password was not set, use the master password
+ keystorePasswordChars = master;
+ }
+ sslContextFactory.setKeyStorePassword(new String(keystorePasswordChars));
+
char[] keypass = null;
try {
keypass = as.getGatewayIdentityPassphrase();
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
index 4cd2160..bf41432 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/RemoteAliasService.java
@@ -63,7 +63,6 @@ public class RemoteAliasService implements AliasService {
PATH_KNOX_SECURITY + "/topology";
public static final String PATH_SEPARATOR = "/";
public static final String DEFAULT_CLUSTER_NAME = "__gateway";
- public static final String GATEWAY_IDENTITY_PASSPHRASE =
"gateway-identity-passphrase";
private static final GatewayMessages LOG =
MessagesFactory.get(GatewayMessages.class);
// N.B. This is ZooKeeper-specific, and should be abstracted when another
registry is supported
@@ -379,15 +378,43 @@ public class RemoteAliasService implements AliasService {
@Override
public char[] getGatewayIdentityPassphrase() throws AliasServiceException {
- char[] passphrase = getPasswordFromAliasForGateway(
- GATEWAY_IDENTITY_PASSPHRASE);
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getIdentityKeyPassphraseAlias());
if (passphrase == null) {
+ // Fall back to the keystore password if a key-specific password was not
explicitly set.
+ passphrase = getGatewayIdentityKeystorePassword();
+ }
+ if (passphrase == null) {
+ // Use the master password if not password was found
+ passphrase = ms.getMasterSecret();
+ }
+ return passphrase;
+ }
+
+ @Override
+ public char[] getGatewayIdentityKeystorePassword() throws
AliasServiceException {
+ return getKeystorePassword(config.getIdentityKeystorePasswordAlias());
+ }
+
+ @Override
+ public char[] getSigningKeyPassphrase() throws AliasServiceException {
+ char[] passphrase =
getPasswordFromAliasForGateway(config.getSigningKeyPassphraseAlias());
+ if (passphrase == null) {
+ // Fall back to the keystore password if a key-specific password was not
explicitly set.
+ passphrase = getSigningKeystorePassword();
+ }
+ if (passphrase == null) {
+ // Use the master password if not password was found
passphrase = ms.getMasterSecret();
}
return passphrase;
}
@Override
+ public char[] getSigningKeystorePassword() throws AliasServiceException {
+ return getKeystorePassword(config.getSigningKeystorePasswordAlias());
+ }
+
+ @Override
public void generateAliasForGateway(final String alias)
throws AliasServiceException {
generateAliasForCluster(DEFAULT_CLUSTER_NAME, alias);
@@ -515,6 +542,15 @@ public class RemoteAliasService implements AliasService {
remoteClient);
}
+ private char[] getKeystorePassword(String alias) throws
AliasServiceException {
+ char[] passphrase = getPasswordFromAliasForGateway(alias);
+ if (passphrase == null) {
+ passphrase = ms.getMasterSecret();
+ }
+ return passphrase;
+ }
+
+
/**
* Encrypt the clear text with master password.
* @param clear clear text to be encrypted
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
index 6034889..190d0dc 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
@@ -49,7 +49,6 @@ import com.nimbusds.jose.crypto.RSASSAVerifier;
public class DefaultTokenAuthorityService implements JWTokenAuthority, Service
{
- private static final String SIGNING_KEY_PASSPHRASE =
"signing.key.passphrase";
private static final Set<String> SUPPORTED_SIG_ALGS = new HashSet<>();
private AliasService as;
private KeystoreService ks;
@@ -158,11 +157,8 @@ public class DefaultTokenAuthorityService implements
JWTokenAuthority, Service {
if(signingKeyPassphrase != null) {
return signingKeyPassphrase;
}
- char[] phrase = as.getPasswordFromAliasForGateway(SIGNING_KEY_PASSPHRASE);
- if (phrase == null) {
- phrase = as.getGatewayIdentityPassphrase();
- }
- return phrase;
+
+ return as.getSigningKeyPassphrase();
}
private String getSigningKeyAlias(String signingKeystoreAlias) {
@@ -172,7 +168,7 @@ public class DefaultTokenAuthorityService implements
JWTokenAuthority, Service {
if(signingKeyAlias != null) {
return signingKeyAlias;
}
- return "gateway-identity";
+ return GatewayConfig.DEFAULT_SIGNING_KEY_ALIAS;
}
@Override
@@ -214,7 +210,7 @@ public class DefaultTokenAuthorityService implements
JWTokenAuthority, Service {
RSAPrivateKey key;
char[] passphrase;
try {
- passphrase = as.getPasswordFromAliasForGateway(SIGNING_KEY_PASSPHRASE);
+ passphrase = as.getSigningKeyPassphrase();
if (passphrase != null) {
key = (RSAPrivateKey)
ks.getSigningKey(getSigningKeyAlias(signingKeyAlias),
passphrase);
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
index 309f0ed..33e6dbd 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
@@ -75,7 +75,11 @@ import java.io.PrintStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyStoreException;
import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -590,8 +594,9 @@ public class KnoxCLI extends Configured implements Tool {
out.println("No keystore has been created for the gateway. Please
use the create-cert command or populate with a CA signed cert of your own.");
}
- Certificate cert =
ks.getKeystoreForGateway().getCertificate("gateway-identity");
- String keyStoreDir = getGatewayConfig().getGatewaySecurityDir() +
File.separator + "keystores" + File.separator;
+ GatewayConfig config = getGatewayConfig();
+ Certificate cert =
ks.getKeystoreForGateway().getCertificate(config.getIdentityKeyAlias());
+ String keyStoreDir = config.getGatewayKeystoreDir() + File.separator;
File ksd = new File(keyStoreDir);
if (!ksd.exists()) {
if (!ksd.mkdirs()) {
@@ -616,7 +621,7 @@ public class KnoxCLI extends Configured implements Tool {
out.println("Invalid type for export file provided. Export has not
been done. Please use: [PEM|JKS|JCEKS|PKCS12] default value is PEM.");
}
} catch (KeystoreServiceException e) {
- throw new ServiceLifecycleException("Keystore was not loaded
properly - the provided (or persisted) master secret may not match the password
for the keystore.", e);
+ throw new ServiceLifecycleException("The identity keystore was not
loaded properly - the provided password may not match the password for the
keystore.", e);
}
}
}
@@ -629,14 +634,15 @@ public class KnoxCLI extends Configured implements Tool {
public class CertCreateCommand extends Command {
- public static final String USAGE = "create-cert [--hostname h]";
- public static final String DESC = "The create-cert command creates and
populates\n" +
- "a gateway.jks keystore with a self-signed
certificate\n" +
- "to be used as the gateway identity. It
also adds an alias\n" +
- "to the __gateway-credentials.jceks
credential store for the\n" +
- "key passphrase.";
+ public static final String USAGE = "create-cert [--force] [--hostname h]";
+ public static final String DESC = "The create-cert command populates the
configured identity\n" +
+ "keystore with a self-signed certificate
to be used as the\n" +
+ "gateway identity. If a cert exists and it
is determined to\n" +
+ "not have been generated by Knox, --force
must be specified\n" +
+ "to overwrite it. If a self-signed cert
is created, a\n" +
+ "password for the key will be generated
and stored in the\n" +
+ "__gateway-credentials.jceks credential
store.";
private static final String GATEWAY_CREDENTIAL_STORE_NAME = "__gateway";
- private static final String GATEWAY_IDENTITY_PASSPHRASE =
"gateway-identity-passphrase";
public CertCreateCommand() {
}
@@ -652,8 +658,7 @@ public class KnoxCLI extends Configured implements Tool {
if
(!ks.isCredentialStoreForClusterAvailable(GATEWAY_CREDENTIAL_STORE_NAME)) {
// log.creatingCredentialStoreForGateway();
ks.createCredentialStoreForCluster(GATEWAY_CREDENTIAL_STORE_NAME);
- }
- else {
+ } else {
// log.credentialStoreForGatewayFoundNotCreating();
}
// LET'S NOT GENERATE A DIFFERENT KEY PASSPHRASE BY DEFAULT ANYMORE
@@ -661,7 +666,7 @@ public class KnoxCLI extends Configured implements Tool {
// THEY CAN ADD THE ALIAS EXPLICITLY WITH THE CLI
//as.generateAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME,
GATEWAY_IDENTITY_PASSPHRASE);
} catch (KeystoreServiceException e) {
- throw new ServiceLifecycleException("Keystore was not loaded properly
- the provided (or persisted) master secret may not match the password for the
keystore.", e);
+ throw new ServiceLifecycleException("Keystore was not loaded properly
- the stored password may not match the password for the keystore.", e);
}
try {
@@ -672,20 +677,84 @@ public class KnoxCLI extends Configured implements Tool {
else {
// log.keyStoreForGatewayFoundNotCreating();
}
- char[] passphrase =
as.getPasswordFromAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME,
GATEWAY_IDENTITY_PASSPHRASE);
- if (passphrase == null) {
- MasterService ms = services.getService("MasterService");
- passphrase = ms.getMasterSecret();
- }
- ks.addSelfSignedCertForGateway("gateway-identity", passphrase,
hostname);
+
+
+ GatewayConfig config = getGatewayConfig();
+
+ if ( !isForceRequired(config, ks) || force) {
+ char[] passphrase = as.getGatewayIdentityPassphrase();
+ if (passphrase == null) {
+ MasterService ms = services.getService("MasterService");
+ passphrase = ms.getMasterSecret();
+ }
+ ks.addSelfSignedCertForGateway(config.getIdentityKeyAlias(),
passphrase, hostname);
// logAndValidateCertificate();
- out.println("Certificate gateway-identity has been successfully
created.");
+ out.println("Certificate " + config.getIdentityKeyAlias() + " has
been successfully created.");
+ } else {
+ // require --force to replace...
+ out.println("A non-self-signed certificate has already been
installed in the configured keystore. " +
+ "Please use --force if you wish to overwrite it with a
generated self-signed certificate.");
+ }
} catch (KeystoreServiceException e) {
- throw new ServiceLifecycleException("Keystore was not loaded properly
- the provided (or persisted) master secret may not match the password for the
keystore.", e);
+ throw new ServiceLifecycleException("The identity keystore was not
loaded properly - the provided password may not match the password for the
keystore.", e);
}
}
}
+ /**
+ * Determines if <code>--force</code> should be used inorder to not
accidentally overwrite a
+ * real certificate.
+ * <p>
+ * <p>
+ * All of the following must be met for <code>--force</code> to <b>NOT</b>
be required:
+ * <ul>
+ * <li>The path to the keystore file is the default path: <code>[Gateway
Keystore Directory]/gateway.jks</code></li>
+ * <li>The alias name for the key is the default name:
<code>gateway-identity</code></li>
+ * <li>The relevant certificate does not exist or is self-signed</li>
+ * <li>The relevant certificate has a subject name ending in
"OU=Test,O=Hadoop,L=Test,ST=Test,C=US"</li>
+ * </ul>
+ *
+ * @param config the Gateway configuration
+ * @param ks a {@link KeystoreService} implementation
+ * @return <code>true</code> if <code>--force</code> is required; otherwise
<code>false</code>
+ */
+ private boolean isForceRequired(GatewayConfig config, KeystoreService ks) {
+
+ // Test the path of the keystore file
+ Path defaultKeystorePath = Paths.get(config.getGatewayKeystoreDir(),
GatewayConfig.DEFAULT_GATEWAY_KEYSTORE_NAME).toAbsolutePath();
+ Path actualKeystorePath =
Paths.get(config.getIdentityKeystorePath()).toAbsolutePath();
+ if (!defaultKeystorePath.equals(actualKeystorePath)) {
+ // The path is not the default path: --force is required
+ return true;
+ }
+
+ // Test the alias name for the key
+ if
(!GatewayConfig.DEFAULT_IDENTITY_KEY_ALIAS.equals(config.getIdentityKeyAlias()))
{
+ // The alias name for the key is not the default name
(gateway-identity): --force is required
+ return true;
+ }
+
+ // Test the certificate
+ try {
+ Certificate certificate = ks.getCertificateForGateway();
+
+ if (certificate instanceof X509Certificate) {
+ if (!X509CertificateUtil.isSelfSignedCertificate(certificate)) {
+ // The relevant certificate exists and is not self-signed: --force
is required
+ return true;
+ } else if (!((X509Certificate)
certificate).getSubjectDN().getName().matches(".*?,\\s*OU=Test,\\s*O=Hadoop,\\s*L=Test,\\s*ST=Test,\\s*C=US"))
{
+ // The subject name of certificate does not end with
"OU=Test,O=Hadoop,L=Test,ST=Test,C=US": --force is required
+ return true;
+ }
+ }
+ } catch (KeyStoreException | KeystoreServiceException e) {
+ // A certificate was (probably) not previously created...
+ }
+
+ // All indicators point to a previously created test certificate: --force
is not required
+ return false;
+ }
+
@Override
public String getUsage() {
return USAGE + ":\n\n" + DESC;
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
index ffd9ac3..dd85793 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
@@ -16,10 +16,12 @@
*/
package org.apache.knox.gateway.config.impl;
+import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.test.TestUtils;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
+import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -32,6 +34,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -292,5 +295,57 @@ public class GatewayConfigImplTest {
assertTrue(names.contains("default"));
}
+ // KNOX-1756
+ @Test
+ public void testCustomIdentityKeystoreOptions() {
+ GatewayConfigImpl config = new GatewayConfigImpl();
+
+ // Validate default options (backwards compatibility)
+ assertEquals("gateway-identity", config.getIdentityKeyAlias());
+ assertEquals("gateway-identity-passphrase",
config.getIdentityKeyPassphraseAlias());
+ assertEquals("gateway-identity", config.getSigningKeyAlias());
+ assertEquals("gateway-identity-passphrase",
config.getSigningKeyPassphraseAlias());
+ assertNull(config.getSigningKeystoreName());
+
+ // Validate default options (new)
+ assertEquals(GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS,
config.getIdentityKeystorePasswordAlias());
+ assertEquals(GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE,
config.getIdentityKeystoreType());
+ assertEquals(Paths.get(config.getGatewayKeystoreDir(),
"gateway.jks").toAbsolutePath().toString(),
+ config.getIdentityKeystorePath());
+
+ // By default the signing keystore name will not be set, so the values
will be taken from the identity's configs
+ assertEquals(config.getIdentityKeystorePath(),
config.getSigningKeystorePath());
+ assertEquals(config.getIdentityKeystorePasswordAlias(),
config.getSigningKeystorePasswordAlias());
+ assertEquals(config.getIdentityKeystoreType(),
config.getSigningKeystoreType());
+ assertEquals(config.getIdentityKeyAlias(), config.getSigningKeyAlias());
+ assertEquals(config.getIdentityKeyPassphraseAlias(),
config.getSigningKeyPassphraseAlias());
+
+ String tlsKeystorePath = Paths.get("custom", "keystore", "path",
"keystore.p12").toString();
+
+ // Validate changed options
+ config.set("gateway.tls.key.alias", "custom_key_alias");
+ config.set("gateway.tls.key.passphrase.alias",
"custom_key_passphrase_alias");
+ config.set("gateway.tls.keystore.path", tlsKeystorePath);
+ config.set("gateway.tls.keystore.type", "PKCS12");
+ config.set("gateway.tls.keystore.password.alias",
"custom_keystore_password_alias");
+
+ config.set("gateway.signing.key.alias", "custom_key_alias");
+ config.set("gateway.signing.key.passphrase.alias",
"custom_key_passphrase_alias");
+ config.set("gateway.signing.keystore.name", "custom_keystore_name");
+ config.set("gateway.signing.keystore.type", "PKCS12");
+ config.set("gateway.signing.keystore.password.alias",
"custom_keystore_password_alias");
+
+ assertEquals("custom_key_alias", config.getIdentityKeyAlias());
+ assertEquals("custom_key_passphrase_alias",
config.getIdentityKeyPassphraseAlias());
+ assertEquals(tlsKeystorePath, config.getIdentityKeystorePath());
+ assertEquals("PKCS12", config.getIdentityKeystoreType());
+ assertEquals("custom_keystore_password_alias",
config.getIdentityKeystorePasswordAlias());
+
+ assertEquals("custom_key_alias", config.getSigningKeyAlias());
+ assertEquals("custom_key_passphrase_alias",
config.getSigningKeyPassphraseAlias());
+ assertEquals("custom_keystore_name", config.getSigningKeystoreName());
+ assertEquals("PKCS12", config.getSigningKeystoreType());
+ assertEquals("custom_keystore_password_alias",
config.getSigningKeystorePasswordAlias());
+ }
}
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/CryptoServiceTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/CryptoServiceTest.java
index 3204630..c0dd1a1 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/CryptoServiceTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/CryptoServiceTest.java
@@ -105,6 +105,21 @@ public class CryptoServiceTest {
public char[] getGatewayIdentityPassphrase() throws
AliasServiceException {
return null;
}
+
+ @Override
+ public char[] getGatewayIdentityKeystorePassword() throws
AliasServiceException {
+ return null;
+ }
+
+ @Override
+ public char[] getSigningKeyPassphrase() throws AliasServiceException {
+ return new char[0];
+ }
+
+ @Override
+ public char[] getSigningKeystorePassword() throws AliasServiceException {
+ return new char[0];
+ }
};
cs = new DefaultCryptoService();
((DefaultCryptoService)cs).setAliasService(as);
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
index 4b0ea28..07faa11 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
@@ -52,15 +52,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
@@ -93,15 +98,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
@@ -135,15 +145,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
@@ -176,15 +191,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
@@ -218,15 +238,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
@@ -266,15 +291,20 @@ public class DefaultTokenAuthorityServiceTest {
basedir = new File(".").getCanonicalPath();
}
- EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes");
-
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir +
"/target/test-classes").anyTimes();
+ EasyMock.expect(config.getGatewayKeystoreDir()).andReturn(basedir +
"/target/test-classes/keystores").anyTimes();
+
EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks").anyTimes();
+ EasyMock.expect(config.getSigningKeystorePath()).andReturn(basedir +
"/target/test-classes/keystores/server-keystore.jks").anyTimes();
+
EasyMock.expect(config.getSigningKeystorePasswordAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeyPassphraseAlias()).andReturn(GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS).anyTimes();
+
EasyMock.expect(config.getSigningKeystoreType()).andReturn("jks").anyTimes();
EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
MasterService ms = EasyMock.createNiceMock(MasterService.class);
EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
AliasService as = EasyMock.createNiceMock(AliasService.class);
-
EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
EasyMock.expect(as.getSigningKeyPassphrase()).andReturn("horton".toCharArray()).anyTimes();
EasyMock.replay(principal, config, ms, as);
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
index 7d3a6be..456d548 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
@@ -17,6 +17,13 @@
*/
package org.apache.knox.gateway.websockets;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS;
+
import com.mycila.xmltool.XMLDoc;
import com.mycila.xmltool.XMLTag;
import org.apache.commons.io.FileUtils;
@@ -50,6 +57,8 @@ import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -67,6 +76,8 @@ import java.util.concurrent.TimeUnit;
*/
public class BadUrlTest {
+ private static final String TEST_KEY_ALIAS = "test-identity";
+
/**
* Non-existant backend websocket server
*/
@@ -90,6 +101,10 @@ public class BadUrlTest {
private static URI serverUri;
private static File topoDir;
+ private static Path dataDir;
+ private static Path securityDir;
+ private static Path keystoresDir;
+ private static Path keystoreFile;
public BadUrlTest() {
super();
@@ -97,6 +112,12 @@ public class BadUrlTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
+ topoDir = createDir();
+ dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath();
+ securityDir = dataDir.resolve("security");
+ keystoresDir = securityDir.resolve("keystores");
+ keystoreFile = keystoresDir.resolve("tls.jks");
+
startGatewayServer();
}
@@ -170,7 +191,6 @@ public class BadUrlTest {
throws IOException {
services = new DefaultGatewayServices();
- topoDir = createDir();
URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
final File descriptor = new File(topoDir, "websocket.xml");
@@ -200,9 +220,6 @@ public class BadUrlTest {
EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
.anyTimes();
- EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
- .andReturn(topoDir.toString()).anyTimes();
-
/* Websocket configs */
EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
.anyTimes();
@@ -240,6 +257,58 @@ public class BadUrlTest {
.andReturn(Collections.emptyList())
.anyTimes();
+ EasyMock.expect(gatewayConfig.getGatewayDataDir())
+ .andReturn(dataDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
+ .andReturn(securityDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewayKeystoreDir())
+ .andReturn(keystoresDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystoreType())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias())
+ .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias())
+ .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystoreType())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
EasyMock.replay(gatewayConfig);
try {
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
index 80c6458..076d084 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
@@ -48,6 +48,8 @@ import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -56,6 +58,12 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -80,6 +88,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
* @since 0.10
*/
public class WebsocketEchoTest {
+ private static final String TEST_KEY_ALIAS = "test-identity";
/**
* Simulate backend websocket
@@ -108,6 +117,10 @@ public class WebsocketEchoTest {
private static URI serverUri;
private static File topoDir;
+ private static Path dataDir;
+ private static Path securityDir;
+ private static Path keystoresDir;
+ private static Path keystoreFile;
public WebsocketEchoTest() {
super();
@@ -115,6 +128,12 @@ public class WebsocketEchoTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
+ topoDir = createDir();
+ dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath();
+ securityDir = dataDir.resolve("security");
+ keystoresDir = securityDir.resolve("keystores");
+ keystoreFile = keystoresDir.resolve("tls.jks");
+
startWebsocketServer();
startGatewayServer();
}
@@ -255,7 +274,6 @@ public class WebsocketEchoTest {
private static void setupGatewayConfig(final String backend) throws
IOException {
services = new DefaultGatewayServices();
- topoDir = createDir();
URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
final File descriptor = new File(topoDir, "websocket.xml");
@@ -285,9 +303,6 @@ public class WebsocketEchoTest {
EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
.anyTimes();
- EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
- .andReturn(topoDir.toString()).anyTimes();
-
/* Websocket configs */
EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
.anyTimes();
@@ -325,6 +340,59 @@ public class WebsocketEchoTest {
.andReturn(Collections.emptyList())
.anyTimes();
+ EasyMock.expect(gatewayConfig.getGatewayDataDir())
+ .andReturn(dataDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
+ .andReturn(securityDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewayKeystoreDir())
+ .andReturn(keystoresDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystoreType())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias())
+ .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias())
+ .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystoreType())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
+
EasyMock.replay(gatewayConfig);
try {
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
index ce064eb..2637922 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
@@ -17,6 +17,13 @@
*/
package org.apache.knox.gateway.websockets;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE;
+import static
org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS;
+
import com.mycila.xmltool.XMLDoc;
import com.mycila.xmltool.XMLTag;
import org.apache.commons.io.FileUtils;
@@ -52,6 +59,8 @@ import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -66,6 +75,8 @@ import java.util.concurrent.TimeUnit;
*
*/
public class WebsocketMultipleConnectionTest {
+ private static final String TEST_KEY_ALIAS = "test-identity";
+
/**
* Simulate backend websocket
*/
@@ -93,6 +104,10 @@ public class WebsocketMultipleConnectionTest {
private static URI serverUri;
private static File topoDir;
+ private static Path dataDir;
+ private static Path securityDir;
+ private static Path keystoresDir;
+ private static Path keystoreFile;
/**
* Maximum number of open connections to test.
@@ -105,6 +120,11 @@ public class WebsocketMultipleConnectionTest {
@BeforeClass
public static void startServers() throws Exception {
+ topoDir = createDir();
+ dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath();
+ securityDir = dataDir.resolve("security");
+ keystoresDir = securityDir.resolve("keystores");
+ keystoreFile = keystoresDir.resolve("tls.jks");
startWebsocketServer();
startGatewayServer();
@@ -231,7 +251,6 @@ public class WebsocketMultipleConnectionTest {
throws IOException {
services = new DefaultGatewayServices();
- topoDir = createDir();
URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
final File descriptor = new File(topoDir, "websocket.xml");
@@ -261,9 +280,6 @@ public class WebsocketMultipleConnectionTest {
EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
.anyTimes();
- EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
- .andReturn(topoDir.toString()).anyTimes();
-
/* Websocket configs */
EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
.anyTimes();
@@ -301,6 +317,58 @@ public class WebsocketMultipleConnectionTest {
.andReturn(Collections.emptyList())
.anyTimes();
+ EasyMock.expect(gatewayConfig.getGatewayDataDir())
+ .andReturn(dataDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
+ .andReturn(securityDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getGatewayKeystoreDir())
+ .andReturn(keystoresDir.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystoreType())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias())
+ .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias())
+ .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias())
+ .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystorePath())
+ .andReturn(keystoreFile.toString())
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeystoreType())
+ .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE)
+ .anyTimes();
+
+ EasyMock.expect(gatewayConfig.getSigningKeyAlias())
+ .andReturn(TEST_KEY_ALIAS)
+ .anyTimes();
+
EasyMock.replay(gatewayConfig);
try {
diff --git
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
index c9362f5..2719c63 100644
---
a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
+++
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
@@ -178,11 +178,11 @@ public class TokenResource {
long expires = getExpiry();
if (endpointPublicCert == null) {
- // acquire PEM for gateway-identity of this gateway instance
+ // acquire PEM for gateway identity of this gateway instance
KeystoreService ks =
services.getService(GatewayServices.KEYSTORE_SERVICE);
if (ks != null) {
try {
- Certificate cert =
ks.getKeystoreForGateway().getCertificate("gateway-identity");
+ Certificate cert = ks.getCertificateForGateway();
byte[] bytes = cert.getEncoded();
//Base64 encoder = new Base64(76, "\n".getBytes("ASCII"));
endpointPublicCert = Base64.encodeBase64String(bytes);
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index c13ece5..93f17ac 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -39,8 +39,27 @@ public interface GatewayConfig {
String KRB5_DEBUG = "sun.security.krb5.debug";
String KRB5_LOGIN_CONFIG = "java.security.auth.login.config";
String KRB5_USE_SUBJECT_CREDS_ONLY =
"javax.security.auth.useSubjectCredsOnly";
+
+ String IDENTITY_KEYSTORE_PASSWORD_ALIAS =
"gateway.tls.keystore.password.alias";
+ String IDENTITY_KEYSTORE_PATH = "gateway.tls.keystore.path";
+ String IDENTITY_KEYSTORE_TYPE = "gateway.tls.keystore.type";
+ String IDENTITY_KEY_ALIAS = "gateway.tls.key.alias";
+ String IDENTITY_KEY_PASSPHRASE_ALIAS = "gateway.tls.key.passphrase.alias";
+ String DEFAULT_IDENTITY_KEYSTORE_TYPE = "JKS";
+ String DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS =
"gateway-identity-keystore-password";
+ String DEFAULT_IDENTITY_KEY_ALIAS = "gateway-identity";
+ String DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS = "gateway-identity-passphrase";
+ String DEFAULT_GATEWAY_KEYSTORE_NAME = "gateway.jks";
+
String SIGNING_KEYSTORE_NAME = "gateway.signing.keystore.name";
+ String SIGNING_KEYSTORE_PASSWORD_ALIAS =
"gateway.signing.keystore.password.alias";
+ String SIGNING_KEYSTORE_TYPE = "gateway.signing.keystore.type";
String SIGNING_KEY_ALIAS = "gateway.signing.key.alias";
+ String SIGNING_KEY_PASSPHRASE_ALIAS = "gateway.signing.key.passphrase.alias";
+ String DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS = "signing.keystore.password";
+ String DEFAULT_SIGNING_KEYSTORE_TYPE = "JKS";
+ String DEFAULT_SIGNING_KEY_ALIAS = "gateway-identity";
+ String DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS = "signing.key.passphrase";
String REMOTE_CONFIG_REGISTRY_TYPE = "type";
String REMOTE_CONFIG_REGISTRY_ADDRESS = "address";
@@ -94,6 +113,16 @@ public interface GatewayConfig {
String getGatewaySecurityDir();
+ /**
+ * Returns the path to the Gateway's keystore directory
+ * <p>
+ * This path is generally calculated to be a subdirectory named "keystores"
under the configured
+ * "security" directory. However, it may be possible for it to be configured
as something else.
+ *
+ * @return the path to the Gateway's keystore directory
+ */
+ String getGatewayKeystoreDir();
+
String getGatewayDeploymentDir();
InetSocketAddress getGatewayAddress() throws UnknownHostException;
@@ -158,10 +187,81 @@ public interface GatewayConfig {
long getGatewayIdleTimeout();
+ /**
+ * Returns the configured value for the path to the keystore holding the key
and certificate for the
+ * Gateway's TLS identity.
+ *
+ * @return a path to the keystore file; or <code>null</code> if not set
+ */
+ String getIdentityKeystorePath();
+
+ /**
+ * Returns the configured value for the type of the keystore holding the
Gateway's identity.
+ *
+ * @return a keystore type
+ */
+ String getIdentityKeystoreType();
+
+ /**
+ * Returns the configured value for the alias name to use when to looking up
the Gateway's identity
+ * keystore's password.
+ *
+ * @return an alias name
+ */
+ String getIdentityKeystorePasswordAlias();
+
+ /**
+ * Returns the configured value for the alias name to use when to looking up
the Gateway's identity
+ * from the Gateway's identity keystore.
+ *
+ * @return an alias name
+ */
+ String getIdentityKeyAlias();
+
+ /**
+ * Returns the configured value for the alias name to use when to looking up
the Gateway's identity
+ * key's password.
+ *
+ * @return an alias name
+ */
+ String getIdentityKeyPassphraseAlias();
+
String getSigningKeystoreName();
+ /**
+ * Returns the calculated value for the path to the keystore holding the key
and certificate for the
+ * Gateway's signing key.
+ *
+ * @return a path to the keystore file; or <code>null</code> if not set
+ */
+ String getSigningKeystorePath();
+
+ /**
+ * Returns the configured value for the type of the keystore holding the
Gateway's signing key.
+ *
+ * @return a keystore type
+ */
+ String getSigningKeystoreType();
+
String getSigningKeyAlias();
+ /**
+ * Returns the configured value for the alias name to use when to looking up
the Gateway's signing
+ * keystore's password.
+ *
+ * @return an alias name
+ */
+ String getSigningKeystorePasswordAlias();
+
+ /**
+ * Returns the configured value for the alias name to use when to looking up
the signing key's
+ * password.
+ *
+ * @return an alias name
+ */
+ String getSigningKeyPassphraseAlias();
+
+
List<String> getGlobalRulesServices();
/**
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/AliasService.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/AliasService.java
index 29fdc44..7a7f76d 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/AliasService.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/AliasService.java
@@ -47,6 +47,12 @@ public interface AliasService extends Service {
char[] getGatewayIdentityPassphrase() throws AliasServiceException;
+ char[] getGatewayIdentityKeystorePassword() throws AliasServiceException;
+
+ char[] getSigningKeyPassphrase() throws AliasServiceException;
+
+ char[] getSigningKeystorePassword() throws AliasServiceException;
+
void generateAliasForGateway(String alias)
throws AliasServiceException;
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/CryptoService.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/CryptoService.java
index e2ccd2a..0e927bd 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/CryptoService.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/CryptoService.java
@@ -28,7 +28,7 @@ public interface CryptoService extends Service {
byte[] decryptForCluster(String clusterName, String alias, byte[]
cipherText, byte[] iv, byte[] salt);
- boolean verify(String algorithm, String alias, String payloadToSign, byte[]
signaturePayload);
+ boolean verify(String algorithm, String payloadToSign, byte[]
signaturePayload);
- byte[] sign(String algorithm, String alias, String payloadToSign);
+ byte[] sign(String algorithm, String payloadToSign);
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
index 5c21d90..a1a843f 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
@@ -19,6 +19,8 @@ package org.apache.knox.gateway.services.security;
import java.security.Key;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
public interface KeystoreService {
@@ -36,6 +38,10 @@ public interface KeystoreService {
Key getKeyForGateway(String alias, char[] passphrase) throws
KeystoreServiceException;
+ Key getKeyForGateway(char[] passphrase) throws KeystoreServiceException;
+
+ Certificate getCertificateForGateway() throws KeystoreServiceException,
KeyStoreException;
+
Key getSigningKey(String alias, char[] passphrase) throws
KeystoreServiceException;
Key getSigningKey(String keystoreName, String alias, char[] passphrase)
throws KeystoreServiceException;
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/SSLService.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/SSLService.java
index 5704d32..3a6874d 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/SSLService.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/SSLService.java
@@ -25,5 +25,5 @@ import java.security.cert.CertificateException;
import org.apache.knox.gateway.services.Service;
public interface SSLService extends Service {
- Object buildSslContextFactory(String gatewayHomeDir) throws
KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException;
+ Object buildSslContextFactory(String keystoreFileName, String keystoreType,
String alias) throws KeyStoreException, IOException, CertificateException,
NoSuchAlgorithmException;
}
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
index d69b678..ffa5759 100644
---
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
@@ -78,22 +78,22 @@ public class BaseKeystoreService {
return Files.newOutputStream( file.toPath() );
}
- protected void createKeystore(String filename, String keystoreType) throws
KeystoreServiceException {
+ 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, masterService.getMasterSecret() );
+ 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) throws KeyStoreException, IOException {
+ 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, masterService.getMasterSecret() );
+ keyStore.load( input, password );
return true;
} catch (NoSuchAlgorithmException | CertificateException e) {
LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e );
@@ -105,10 +105,10 @@ public class BaseKeystoreService {
return false;
}
- protected KeyStore getKeystore(final File keyStoreFile, String storeType)
throws KeystoreServiceException {
+ protected KeyStore getKeystore(final File keyStoreFile, String storeType,
char[] password) throws KeystoreServiceException {
KeyStore credStore;
try {
- credStore = loadKeyStore( keyStoreFile, masterService.getMasterSecret(),
storeType);
+ credStore = loadKeyStore( keyStoreFile, password, storeType);
} catch (CertificateException | IOException | NoSuchAlgorithmException |
KeyStoreException e) {
LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e );
throw new KeystoreServiceException(e);
@@ -164,11 +164,11 @@ public class BaseKeystoreService {
}
}
- protected void writeKeystoreToFile(final KeyStore keyStore, final File file)
+ 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, masterService.getMasterSecret() );
+ keyStore.store( out, password );
}
}
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
index 854ccd0..8d86eab 100644
---
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
@@ -55,12 +55,12 @@ public class CMFKeystoreService extends BaseKeystoreService
{
public void createKeystore() throws KeystoreServiceException {
String filename = keyStoreDir + serviceName + ".jks";
- createKeystore(filename, "JKS");
+ createKeystore(filename, "JKS", masterService.getMasterSecret());
}
public KeyStore getKeystore() throws KeystoreServiceException {
final File keyStoreFile = new File( keyStoreDir + serviceName );
- return getKeystore(keyStoreFile, "JKS");
+ return getKeystore(keyStoreFile, "JKS", masterService.getMasterSecret());
}
public void addSelfSignedCert(String alias, char[] passphrase)
@@ -77,7 +77,7 @@ public class CMFKeystoreService extends BaseKeystoreService {
privateKS.setKeyEntry(alias, KPair.getPrivate(),
passphrase,
new java.security.cert.Certificate[]{cert});
- writeKeystoreToFile(privateKS, new File( keyStoreDir + serviceName ));
+ writeKeystoreToFile(privateKS, new File( keyStoreDir + serviceName ),
masterService.getMasterSecret());
} else {
throw new IOException("Unable to open gateway keystore.");
}
@@ -88,13 +88,13 @@ public class CMFKeystoreService extends BaseKeystoreService
{
public void createCredentialStore() throws KeystoreServiceException {
String filename = keyStoreDir + serviceName + CREDENTIALS_SUFFIX;
- createKeystore(filename, "JCEKS");
+ createKeystore(filename, "JCEKS", masterService.getMasterSecret());
}
public boolean isCredentialStoreAvailable() throws KeystoreServiceException {
final File keyStoreFile = new File( keyStoreDir + serviceName +
CREDENTIALS_SUFFIX );
try {
- return isKeystoreAvailable(keyStoreFile, "JCEKS");
+ return isKeystoreAvailable(keyStoreFile, "JCEKS",
masterService.getMasterSecret());
} catch (KeyStoreException | IOException e) {
throw new KeystoreServiceException(e);
}
@@ -103,7 +103,7 @@ public class CMFKeystoreService extends BaseKeystoreService
{
public boolean isKeystoreAvailable() throws KeystoreServiceException {
final File keyStoreFile = new File( keyStoreDir + serviceName + ".jks" );
try {
- return isKeystoreAvailable(keyStoreFile, "JKS");
+ return isKeystoreAvailable(keyStoreFile, "JKS",
masterService.getMasterSecret());
} catch (KeyStoreException | IOException e) {
throw new KeystoreServiceException(e);
}
@@ -124,7 +124,7 @@ public class CMFKeystoreService extends BaseKeystoreService
{
public KeyStore getCredentialStore() throws KeystoreServiceException {
final File keyStoreFile = new File( keyStoreDir + serviceName +
CREDENTIALS_SUFFIX );
- return getKeystore(keyStoreFile, "JCEKS");
+ return getKeystore(keyStoreFile, "JCEKS", masterService.getMasterSecret());
}
public void addCredential(String alias, String value) throws
KeystoreServiceException {
@@ -132,7 +132,7 @@ public class CMFKeystoreService extends BaseKeystoreService
{
addCredential(alias, value, ks);
final File keyStoreFile = new File( keyStoreDir + serviceName +
CREDENTIALS_SUFFIX );
try {
- writeKeystoreToFile(ks, keyStoreFile);
+ writeKeystoreToFile(ks, keyStoreFile, masterService.getMasterSecret());
} catch (KeyStoreException | NoSuchAlgorithmException |
CertificateException | IOException e) {
LOG.failedToAddCredential(e);
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
index 8e0a370..7e9e20c 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
@@ -312,5 +312,21 @@ public class X509CertificateUtil {
writeCertificateToKeyStore(cert, file, "pkcs12");
}
+ /**
+ * Tests the X509 certificate to see if it was self-signed.
+ * <p>
+ * The certificate is determined to be self-signed if the subject DN is the
same as the issuer DN
+ *
+ * @param certificate the {@link X509Certificate} to test
+ * @return <code>true</code> if the X509 certficate is self-signed;
otherwise <code>false</code>
+ */
+ public static boolean isSelfSignedCertificate(Certificate certificate) {
+ if (certificate instanceof X509Certificate) {
+ X509Certificate x509Certificate = (X509Certificate) certificate;
+ return
x509Certificate.getSubjectDN().equals(x509Certificate.getIssuerDN());
+ } else {
+ return false;
+ }
+ }
}
diff --git
a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index ed89a2f..35b0ce9 100644
---
a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++
b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -22,9 +22,11 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
-import java.io.File;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -44,15 +46,15 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
public static final int DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT = 60000;
public static final int DEFAULT_WEBSOCKET_IDLE_TIMEOUT = 300000;
- private String gatewayHomeDir = "gateway-home";
+ private Path gatewayHomePath = Paths.get("gateway-home");
private String hadoopConfDir = "hadoop";
private String gatewayHost = "localhost";
private int gatewayPort;
private String gatewayPath = "gateway";
private boolean hadoopKerberosSecured;
- private String kerberosConfig = "/etc/knox/conf/krb5.conf";
+ private String kerberosConfig;
private boolean kerberosDebugEnabled;
- private String kerberosLoginConfig = "/etc/knox/conf/krb5JAASLogin.conf";
+ private String kerberosLoginConfig;
private String frontendUrl;
private boolean xForwardedEnabled = true;
private String gatewayApplicationsDir;
@@ -68,37 +70,80 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
private int backupVersionLimit = -1;
private long backupAgeLimit = -1;
+ public GatewayTestConfig() {
+
+ Iterable<Path> paths = FileSystems.getDefault().getRootDirectories();
+ Path rootPath = null;
+ for (Path path : paths) {
+ rootPath = path;
+ }
+ if (rootPath == null) {
+ rootPath = Paths.get("/");
+ }
+
+ // /etc/knox/conf
+ Path etcConfKnoxPath =
rootPath.resolve("etc").resolve("knox").resolve("conf");
+
+ // /etc/knox/conf/krb5.conf
+ kerberosConfig = etcConfKnoxPath.resolve("krb5.conf").toString();
+
+ // /etc/knox/conf/krb5JAASLogin.conf
+ kerberosLoginConfig =
etcConfKnoxPath.resolve("krb5JAASLogin.conf").toString();
+ }
+
+
public void setGatewayHomeDir( String gatewayHomeDir ) {
- this.gatewayHomeDir = gatewayHomeDir;
+ this.gatewayHomePath = Paths.get(gatewayHomeDir);
}
public String getGatewayHomeDir() {
- return this.gatewayHomeDir;
+ return gatewayHomePath.toString();
}
@Override
public String getGatewayConfDir() {
- return gatewayHomeDir;
+ return getGatewayConfPath().toString();
+ }
+
+ private Path getGatewayConfPath() {
+ return gatewayHomePath.resolve("conf");
}
@Override
public String getGatewayDataDir() {
- return gatewayHomeDir;
+ return getGatewayDataPath().toString();
+ }
+
+ private Path getGatewayDataPath() {
+ return gatewayHomePath.resolve("data");
}
@Override
public String getGatewaySecurityDir() {
- return gatewayHomeDir + "/security";
+ return getGatewaySecurityPath().toString();
+ }
+
+ private Path getGatewaySecurityPath() {
+ return getGatewayDataPath().resolve("security");
+ }
+
+ @Override
+ public String getGatewayKeystoreDir() {
+ return getGatewayKeystorePath().toString();
+ }
+
+ private Path getGatewayKeystorePath() {
+ return getGatewayDataPath().resolve("keystores");
}
@Override
public String getGatewayTopologyDir() {
- return gatewayHomeDir + "/topologies";
+ return gatewayHomePath.resolve("topologies").toString();
}
@Override
public String getGatewayDeploymentDir() {
- return gatewayHomeDir + "/deployments";
+ return gatewayHomePath.resolve("deployments").toString();
}
@Override
@@ -136,6 +181,31 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
}
@Override
+ public String getIdentityKeystorePath() {
+ return
getGatewayKeystorePath().resolve(DEFAULT_GATEWAY_KEYSTORE_NAME).toString();
+ }
+
+ @Override
+ public String getIdentityKeystoreType() {
+ return DEFAULT_IDENTITY_KEYSTORE_TYPE;
+ }
+
+ @Override
+ public String getIdentityKeystorePasswordAlias() {
+ return DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS;
+ }
+
+ @Override
+ public String getIdentityKeyAlias() {
+ return DEFAULT_IDENTITY_KEY_ALIAS;
+ }
+
+ @Override
+ public String getIdentityKeyPassphraseAlias() {
+ return DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS;
+ }
+
+ @Override
public boolean isSSLEnabled() {
return sslEnabled;
}
@@ -268,8 +338,7 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
if( gatewayServicesDir != null ) {
return gatewayServicesDir;
} else {
- File targetDir = new File( System.getProperty( "user.dir" ),
"target/services" );
- return targetDir.getPath();
+ return Paths.get(System.getProperty("user.dir"), "target",
"services").toString();
}
}
@@ -282,7 +351,7 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
if( gatewayApplicationsDir != null ) {
return gatewayApplicationsDir;
} else {
- return getGatewayConfDir() + "/applications";
+ return getGatewayConfPath().resolve("applications").toString();
}
}
@@ -377,8 +446,28 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
}
@Override
+ public String getSigningKeystorePath() {
+ return
getGatewayKeystorePath().resolve(DEFAULT_GATEWAY_KEYSTORE_NAME).toString();
+ }
+
+ @Override
+ public String getSigningKeystoreType() {
+ return DEFAULT_SIGNING_KEYSTORE_TYPE;
+ }
+
+ @Override
public String getSigningKeyAlias() {
- return null;
+ return DEFAULT_SIGNING_KEY_ALIAS;
+ }
+
+ @Override
+ public String getSigningKeystorePasswordAlias() {
+ return DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS;
+ }
+
+ @Override
+ public String getSigningKeyPassphraseAlias() {
+ return DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS;
}
@Override