[cleanup] separate SSLService into ClientSSLService and ServerSSLService

Separates the SSLService into a ClientSSLService and a ServerSSLService. The ClientSSLService
should be used for client connections and removes the requirement for setting a keystore or a
truststore. The ServerSSLService maintains the existing requirement to have a keystore. Also, fixed
a small issue where the HandshakeWaitingHandlerTests called handshake more than once.

Closes elastic/elasticsearch#622

Original commit: elastic/x-pack-elasticsearch@67b6121b04
This commit is contained in:
jaymode 2015-01-30 11:39:28 -05:00
parent 458daa2323
commit f6b2950323
21 changed files with 844 additions and 365 deletions

View File

@ -6,7 +6,7 @@
package org.elasticsearch.shield.authc.support.ldap;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
@ -19,7 +19,7 @@ import java.net.InetAddress;
*/
public abstract class AbstractLdapSslSocketFactory extends SocketFactory {
protected static SSLService sslService;
protected static ClientSSLService clientSSLService;
private final SSLSocketFactory socketFactory;
@ -27,8 +27,8 @@ public abstract class AbstractLdapSslSocketFactory extends SocketFactory {
* This should only be invoked once to establish a static instance that will be used for each constructor.
*/
@Inject
public static void init(SSLService sslService) {
AbstractLdapSslSocketFactory.sslService = sslService;
public static void init(ClientSSLService sslService) {
AbstractLdapSslSocketFactory.clientSSLService = sslService;
}
public AbstractLdapSslSocketFactory(SSLSocketFactory sslSocketFactory) {
@ -78,7 +78,7 @@ public abstract class AbstractLdapSslSocketFactory extends SocketFactory {
* @param sslSocket
*/
protected void configureSSLSocket(SSLSocket sslSocket) {
sslSocket.setEnabledProtocols(sslService.supportedProtocols());
sslSocket.setEnabledCipherSuites(sslService.ciphers());
sslSocket.setEnabledProtocols(clientSSLService.supportedProtocols());
sslSocket.setEnabledCipherSuites(clientSSLService.ciphers());
}
}

View File

@ -12,8 +12,6 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.InetAddress;
/**
* This factory is needed for JNDI configuration for LDAP connections with hostname verification. Each SSLSocket must
@ -39,7 +37,7 @@ public class HostnameVerifyingLdapSslSocketFactory extends AbstractLdapSslSocket
*/
public static synchronized SocketFactory getDefault() {
if (instance == null) {
instance = new HostnameVerifyingLdapSslSocketFactory(sslService.getSSLSocketFactory());
instance = new HostnameVerifyingLdapSslSocketFactory(clientSSLService.getSSLSocketFactory());
}
return instance;
}

View File

@ -36,7 +36,7 @@ public class LdapSslSocketFactory extends AbstractLdapSslSocketFactory {
*/
public static synchronized SocketFactory getDefault() {
if (instance == null) {
instance = new LdapSslSocketFactory(sslService.getSSLSocketFactory());
instance = new LdapSslSocketFactory(clientSSLService.getSSLSocketFactory());
}
return instance;
}

View File

@ -0,0 +1,254 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.cache.CacheLoader;
import org.elasticsearch.common.cache.LoadingCache;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.primitives.Ints;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.UncheckedExecutionException;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Arrays;
/**
* This service houses the private key and trust managers needed for SSL/TLS negotiation. It is the central place to
* get SSLEngines and SocketFactories.
*/
public abstract class AbstractSSLService extends AbstractComponent {
static final String[] DEFAULT_CIPHERS = new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
static final String[] DEFAULT_SUPPORTED_PROTOCOLS = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
static final int DEFAULT_SESSION_CACHE_SIZE = 1000;
static final String DEFAULT_PROTOCOL = "TLS";
protected LoadingCache<SSLSettings, SSLContext> sslContexts = CacheBuilder.newBuilder().build(new SSLContextCacheLoader());
public AbstractSSLService(Settings settings) {
super(settings);
}
/**
* @return A SSLSocketFactory (for client-side SSL handshaking)
*/
public SSLSocketFactory getSSLSocketFactory() {
return sslContext(ImmutableSettings.EMPTY).getSocketFactory();
}
public String[] supportedProtocols() {
return componentSettings.getAsArray("supported_protocols", DEFAULT_SUPPORTED_PROTOCOLS);
}
public String[] ciphers() {
return componentSettings.getAsArray("ciphers", DEFAULT_CIPHERS);
}
public SSLEngine createSSLEngine() {
return createSSLEngine(ImmutableSettings.EMPTY);
}
public SSLEngine createSSLEngine(Settings settings) {
return createSSLEngine(settings, null, -1);
}
public SSLEngine createSSLEngine(Settings settings, String host, int port) {
String[] ciphers = settings.getAsArray("ciphers", ciphers());
String[] supportedProtocols = settings.getAsArray("supported_protocols", supportedProtocols());
return createSSLEngine(sslContext(settings), ciphers, supportedProtocols, host, port);
}
public SSLContext sslContext() {
return sslContext(ImmutableSettings.EMPTY);
}
protected SSLContext sslContext(Settings settings) {
SSLSettings sslSettings = sslSettings(settings);
try {
return sslContexts.getUnchecked(sslSettings);
} catch (UncheckedExecutionException e) {
// Unwrap ElasticsearchSSLException
if (e.getCause() instanceof ElasticsearchSSLException) {
throw (ElasticsearchSSLException) e.getCause();
} else {
throw new ElasticsearchSSLException("failed to load SSLContext", e);
}
}
}
protected abstract SSLSettings sslSettings(Settings customSettings);
SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) {
SSLEngine sslEngine = sslContext.createSSLEngine(host, port);
try {
sslEngine.setEnabledCipherSuites(ciphers);
} catch (Throwable t) {
throw new ElasticsearchSSLException("failed loading cipher suites [" + Arrays.asList(ciphers) + "]", t);
}
try {
sslEngine.setEnabledProtocols(supportedProtocols);
} catch (IllegalArgumentException e) {
throw new ElasticsearchSSLException("failed setting supported protocols [" + Arrays.asList(supportedProtocols) + "]", e);
}
return sslEngine;
}
private class SSLContextCacheLoader extends CacheLoader<SSLSettings, SSLContext> {
@Override
public SSLContext load(SSLSettings sslSettings) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("using keystore[{}], key_algorithm[{}], truststore[{}], truststore_algorithm[{}], tls_protocol[{}], session_cache_size[{}], session_cache_timeout[{}]",
sslSettings.keyStorePath, sslSettings.keyStoreAlgorithm, sslSettings.trustStorePath, sslSettings.trustStoreAlgorithm, sslSettings.sslProtocol, sslSettings.sessionCacheSize, sslSettings.sessionCacheTimeout);
}
TrustManager[] trustManagers = trustManagers(sslSettings.trustStorePath, sslSettings.trustStorePassword, sslSettings.trustStoreAlgorithm);
KeyManager[] keyManagers = keyManagers(sslSettings.keyStorePath, sslSettings.keyStorePassword, sslSettings.keyStoreAlgorithm, sslSettings.keyPassword);
return createSslContext(keyManagers, trustManagers, sslSettings.sslProtocol, sslSettings.sessionCacheSize, sslSettings.sessionCacheTimeout);
}
private KeyManager[] keyManagers(String keyStore, String keyStorePassword, String keyStoreAlgorithm, String keyPassword) {
if (keyStore == null) {
return null;
}
try {
// Load KeyStore
KeyStore ks = readKeystore(keyStore, keyStorePassword);
// Initialize KeyManagerFactory
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm);
kmf.init(ks, keyPassword.toCharArray());
return kmf.getKeyManagers();
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize a KeyManagerFactory", e);
}
}
private SSLContext createSslContext(KeyManager[] keyManagers, TrustManager[] trustManagers, String sslProtocol, int sessionCacheSize, TimeValue sessionCacheTimeout) {
// Initialize sslContext
try {
SSLContext sslContext = SSLContext.getInstance(sslProtocol);
sslContext.init(keyManagers, trustManagers, null);
sslContext.getServerSessionContext().setSessionCacheSize(sessionCacheSize);
sslContext.getServerSessionContext().setSessionTimeout(Ints.checkedCast(sessionCacheTimeout.seconds()));
return sslContext;
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize the SSLContext", e);
}
}
private TrustManager[] trustManagers(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) {
try {
// Load TrustStore
KeyStore ks = null;
if (trustStorePath != null) {
ks = readKeystore(trustStorePath, trustStorePassword);
}
// Initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
trustFactory.init(ks);
return trustFactory.getTrustManagers();
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize a TrustManagerFactory", e);
}
}
private KeyStore readKeystore(String path, String password) throws Exception {
try (FileInputStream in = new FileInputStream(path)) {
// Load TrustStore
KeyStore ks = KeyStore.getInstance("jks");
assert password != null;
ks.load(in, password.toCharArray());
return ks;
}
}
}
static class SSLSettings {
private static final ESLogger logger = Loggers.getLogger(SSLSettings.class);
String keyStorePath;
String keyStorePassword;
String keyStoreAlgorithm;
String keyPassword;
String trustStorePath;
String trustStorePassword;
String trustStoreAlgorithm;
String sslProtocol;
int sessionCacheSize;
TimeValue sessionCacheTimeout;
SSLSettings(Settings settings, Settings componentSettings) {
keyStorePath = settings.get("keystore.path", componentSettings.get("keystore.path", System.getProperty("javax.net.ssl.keyStore")));
keyStorePassword = settings.get("keystore.password", componentSettings.get("keystore.password", System.getProperty("javax.net.ssl.keyStorePassword")));
keyStoreAlgorithm = settings.get("keystore.algorithm", componentSettings.get("keystore.algorithm", System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm())));
keyPassword = settings.get("keystore.key_password", componentSettings.get("keystore.key_password", keyStorePassword));
// Truststore settings
trustStorePath = settings.get("truststore.path", componentSettings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore")));
trustStorePassword = settings.get("truststore.password", componentSettings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword")));
trustStoreAlgorithm = settings.get("truststore.algorithm", componentSettings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())));
sslProtocol = settings.get("protocol", componentSettings.get("protocol", DEFAULT_PROTOCOL));
sessionCacheSize = settings.getAsInt("session.cache_size", componentSettings.getAsInt("session.cache_size", DEFAULT_SESSION_CACHE_SIZE));
sessionCacheTimeout = settings.getAsTime("session.cache_timeout", componentSettings.getAsTime("session.cache_timeout", DEFAULT_SESSION_CACHE_TIMEOUT));
if (trustStorePath == null) {
if (logger.isDebugEnabled()) {
logger.debug("no truststore defined. using keystore [{}] as truststore", keyStorePath);
}
trustStorePath = keyStorePath;
trustStorePassword = keyStorePassword;
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SSLSettings that = (SSLSettings) o;
if (keyStorePath != null ? !keyStorePath.equals(that.keyStorePath) : that.keyStorePath != null) {
return false;
}
if (sslProtocol != null ? !sslProtocol.equals(that.sslProtocol) : that.sslProtocol != null) {
return false;
}
if (trustStorePath != null ? !trustStorePath.equals(that.trustStorePath) : that.trustStorePath != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = keyStorePath != null ? keyStorePath.hashCode() : 0;
result = 31 * result + (trustStorePath != null ? trustStorePath.hashCode() : 0);
result = 31 * result + (sslProtocol != null ? sslProtocol.hashCode() : 0);
return result;
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldSettingsException;
public class ClientSSLService extends AbstractSSLService {
@Inject
public ClientSSLService(Settings settings) {
super(settings);
}
@Override
protected SSLSettings sslSettings(Settings customSettings) {
SSLSettings sslSettings = new SSLSettings(customSettings, componentSettings);
if (sslSettings.keyStorePath != null) {
if (sslSettings.keyStorePassword == null) {
throw new ShieldSettingsException("no keystore password configured");
}
}
if (sslSettings.trustStorePath != null) {
if (sslSettings.trustStorePassword == null) {
throw new ShieldSettingsException("no truststore password configured");
}
}
return sslSettings;
}
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.support.AbstractShieldModule;
@ -19,6 +20,11 @@ public class SSLModule extends AbstractShieldModule {
@Override
protected void configure(boolean clientMode) {
bind(SSLService.class).asEagerSingleton();
bind(ClientSSLService.class).asEagerSingleton();
if (!clientMode) {
bind(ServerSSLService.class).asEagerSingleton();
} else {
bind(ServerSSLService.class).toProvider(Providers.<ServerSSLService>of(null));
}
}
}

View File

@ -1,257 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.primitives.Ints;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.shield.ShieldSettingsException;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Map;
/**
* This service houses the private key and trust managers needed for SSL/TLS negotiation. It is the central place to
* get SSLEngines and SocketFactories.
*/
public class SSLService extends AbstractComponent {
static final String[] DEFAULT_CIPHERS = new String[]{ "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
static final String[] DEFAULT_SUPPORTED_PROTOCOLS = new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"};
static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
private Map<String, SSLContext> sslContexts = ConcurrentCollections.newConcurrentMap();
@Inject
public SSLService(Settings settings) {
super(settings);
}
/**
* @return An SSLSocketFactory (for client-side SSL handshaking)
*/
public SSLSocketFactory getSSLSocketFactory() {
return getSslContext(ImmutableSettings.EMPTY).getSocketFactory();
}
public String[] supportedProtocols() {
return componentSettings.getAsArray("supported_protocols", DEFAULT_SUPPORTED_PROTOCOLS);
}
public String[] ciphers() {
return componentSettings.getAsArray("ciphers", DEFAULT_CIPHERS);
}
public SSLEngine createSSLEngine() {
return createSSLEngine(ImmutableSettings.EMPTY);
}
public SSLEngine createSSLEngine(Settings settings) {
return createSSLEngine(settings, null, -1);
}
public SSLEngine createSSLEngine(Settings settings, String host, int port) {
String[] ciphers = settings.getAsArray("ciphers", ciphers());
String[] supportedProtocols = settings.getAsArray("supported_protocols", supportedProtocols());
return createSSLEngine(getSslContext(settings), ciphers, supportedProtocols, host, port);
}
//TODO this needs to be removed and the logic folded into the other methods of this class or we create a ClientSSLService class
public SSLEngine createClientSSLEngine() {
return createClientSSLEngine(null, -1);
}
//TODO this needs to be removed and the logic folded into the other methods of this class or we create a ClientSSLService class
public SSLEngine createClientSSLEngine(String host, int port) {
SSLContext sslContext = getClientSSLContext();
return createSSLEngine(sslContext, ciphers(), supportedProtocols(), host, port);
}
//TODO remove this when createClientSSLEngine is removed. Used for tests
SSLContext getClientSSLContext() {
String keyStorePath = componentSettings.get("keystore.path", System.getProperty("javax.net.ssl.keyStore"));
String keyStorePassword = componentSettings.get("keystore.password", System.getProperty("javax.net.ssl.keyStorePassword"));
String keyStoreAlgorithm = componentSettings.get("keystore.algorithm", System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()));
String keyPassword = componentSettings.get("keystore.key_password", keyStorePassword);
String trustStorePath = componentSettings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore"));
String trustStorePassword = componentSettings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword"));
String trustStoreAlgorithm = componentSettings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
if (trustStorePath == null) {
//the keystore will also be the truststore
trustStorePath = keyStorePath;
trustStorePassword = keyStorePassword;
}
//protocols supported: https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
String sslProtocol = componentSettings.get("protocol", "TLS");
// no need for a complex key, same path + protocol define about reusability of a SSLContext
// also no need for pwd verification. If it worked before, it will work again
String key = keyStorePath + trustStorePath + sslProtocol;
SSLContext sslContext = sslContexts.get(key);
if (sslContext == null) {
logger.debug("using keystore[{}], key_algorithm[{}], truststore[{}], truststore_algorithm[{}], tls_protocol[{}]",
keyStorePath, keyStoreAlgorithm, trustStorePath, trustStoreAlgorithm, sslProtocol);
TrustManagerFactory trustFactory;
try {
trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
if (trustStorePath != null) {
trustFactory.init(readKeystore(trustStorePath, trustStorePassword));
} else {
trustFactory.init((KeyStore) null);
}
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize a TrustManagerFactory", e);
}
KeyManager[] keyManagers = null;
if (keyStorePath != null) {
if (keyStorePassword == null) {
throw new ShieldSettingsException("no keystore password configured");
}
keyManagers = createKeyManagerFactory(keyStorePath, keyStorePassword, keyStoreAlgorithm, keyPassword).getKeyManagers();
}
try {
sslContext = SSLContext.getInstance(sslProtocol);
sslContext.init(keyManagers, trustFactory.getTrustManagers(), null);
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize the SSLContext", e);
}
sslContexts.put(key, sslContext);
} else {
logger.trace("found keystore[{}], truststore[{}], tls_protocol[{}] in SSL context cache, reusing", keyStorePath, trustStorePath, sslProtocol);
}
return sslContext;
}
public SSLContext getSslContext() {
return getSslContext(ImmutableSettings.EMPTY);
}
private SSLContext getSslContext(Settings settings) {
String keyStorePath = settings.get("keystore.path", componentSettings.get("keystore.path", System.getProperty("javax.net.ssl.keyStore")));
String keyStorePassword = settings.get("keystore.password", componentSettings.get("keystore.password", System.getProperty("javax.net.ssl.keyStorePassword")));
String keyStoreAlgorithm = settings.get("keystore.algorithm", componentSettings.get("keystore.algorithm", System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm())));
String keyPassword = settings.get("keystore.key_password", componentSettings.get("keystore.key_password", keyStorePassword));
String trustStorePath = settings.get("truststore.path", componentSettings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore")));
String trustStorePassword = settings.get("truststore.password", componentSettings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword")));
String trustStoreAlgorithm = settings.get("truststore.algorithm", componentSettings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())));
if (trustStorePath == null) {
//the keystore will also be the truststore
trustStorePath = keyStorePath;
trustStorePassword = keyStorePassword;
}
if (keyStorePath == null) {
throw new ShieldSettingsException("no keystore configured");
}
if (keyStorePassword == null) {
throw new ShieldSettingsException("no keystore password configured");
}
//protocols supported: https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
String sslProtocol = componentSettings.get("protocol", "TLS");
// no need for a complex key, same path + protocol define about reusability of a SSLContext
// also no need for pwd verification. If it worked before, it will work again
String key = keyStorePath + trustStorePath + sslProtocol;
SSLContext sslContext = sslContexts.get(key);
if (sslContext == null) {
int sessionCacheSize = settings.getAsInt("session.cache_size", componentSettings.getAsInt("session.cache_size", 1000));
TimeValue sessionCacheTimeout = settings.getAsTime("session.cache_timeout", componentSettings.getAsTime("session.cache_timeout", DEFAULT_SESSION_CACHE_TIMEOUT));
logger.debug("using keystore[{}], key_algorithm[{}], truststore[{}], truststore_algorithm[{}], tls_protocol[{}], session_cache_size[{}], session_cache_timeout[{}]",
keyStorePath, keyStoreAlgorithm, trustStorePath, trustStoreAlgorithm, sslProtocol, sessionCacheSize, sessionCacheTimeout);
TrustManagerFactory trustFactory = getTrustFactory(trustStorePath, trustStorePassword, trustStoreAlgorithm);
KeyManagerFactory keyManagerFactory = createKeyManagerFactory(keyStorePath, keyStorePassword, keyStoreAlgorithm, keyPassword);
sslContext = createSslContext(keyManagerFactory, trustFactory, sslProtocol, sessionCacheSize, sessionCacheTimeout);
sslContexts.put(key, sslContext);
} else {
logger.trace("found keystore[{}], truststore[{}], tls_protocol[{}] in SSL context cache, reusing", keyStorePath, trustStorePath, sslProtocol);
}
return sslContext;
}
private SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) {
SSLEngine sslEngine = sslContext.createSSLEngine(host, port);
try {
sslEngine.setEnabledCipherSuites(ciphers);
} catch (Throwable t) {
throw new ElasticsearchSSLException("failed loading cipher suites [" + Arrays.asList(ciphers) + "]", t);
}
try {
sslEngine.setEnabledProtocols(supportedProtocols);
} catch (IllegalArgumentException e) {
throw new ElasticsearchSSLException("failed setting supported protocols [" + Arrays.asList(supportedProtocols) + "]", e);
}
return sslEngine;
}
private KeyManagerFactory createKeyManagerFactory(String keyStore, String keyStorePassword, String keyStoreAlgorithm, String keyPassword) {
try {
// Load KeyStore
KeyStore ks = readKeystore(keyStore, keyStorePassword);
// Initialize KeyManagerFactory
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm);
kmf.init(ks, keyPassword.toCharArray());
return kmf;
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize a KeyManagerFactory", e);
}
}
private SSLContext createSslContext(KeyManagerFactory keyManagerFactory, TrustManagerFactory trustFactory, String sslProtocol, int sessionCacheSize, TimeValue sessionCacheTimeout) {
// Initialize sslContext
try {
SSLContext sslContext = SSLContext.getInstance(sslProtocol);
sslContext.init(keyManagerFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
sslContext.getServerSessionContext().setSessionCacheSize(sessionCacheSize);
sslContext.getServerSessionContext().setSessionTimeout(Ints.checkedCast(sessionCacheTimeout.seconds()));
return sslContext;
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize the SSLContext", e);
}
}
private TrustManagerFactory getTrustFactory(String trustStore, String trustStorePassword, String trustStoreAlgorithm) {
try {
// Load TrustStore
KeyStore ks = readKeystore(trustStore, trustStorePassword);
// Initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
trustFactory.init(ks);
return trustFactory;
} catch (Exception e) {
throw new ElasticsearchSSLException("failed to initialize a TrustManagerFactory", e);
}
}
private KeyStore readKeystore(String path, String password) throws Exception {
try (FileInputStream in = new FileInputStream(path)) {
// Load TrustStore
KeyStore ks = KeyStore.getInstance("jks");
ks.load(in, password == null ? null : password.toCharArray());
return ks;
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldSettingsException;
public class ServerSSLService extends AbstractSSLService {
@Inject
public ServerSSLService(Settings settings) {
super(settings);
}
@Override
protected SSLSettings sslSettings(Settings customSettings) {
SSLSettings sslSettings = new SSLSettings(customSettings, componentSettings);
if (sslSettings.keyStorePath == null) {
throw new ShieldSettingsException("no keystore configured");
}
if (sslSettings.keyStorePassword == null) {
throw new ShieldSettingsException("no keystore password configured");
}
assert sslSettings.trustStorePath != null;
if (sslSettings.trustStorePassword == null) {
throw new ShieldSettingsException("no truststore password configured");
}
return sslSettings;
}
}

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.http.netty.NettyHttpServerTransport;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.shield.transport.filter.IPFilter;
import javax.net.ssl.SSLEngine;
@ -24,12 +24,12 @@ import javax.net.ssl.SSLEngine;
public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
private final IPFilter ipFilter;
private final SSLService sslService;
private final ServerSSLService sslService;
private final boolean ssl;
@Inject
public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays,
IPFilter ipFilter, SSLService sslService) {
IPFilter ipFilter, ServerSSLService sslService) {
super(settings, networkService, bigArrays);
this.ipFilter = ipFilter;
this.ssl = settings.getAsBoolean("shield.http.ssl", false);

View File

@ -11,9 +11,11 @@ import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.netty.channel.*;
import org.elasticsearch.common.netty.handler.ssl.SslHandler;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.shield.transport.filter.IPFilter;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.netty.NettyTransport;
@ -30,17 +32,19 @@ public class ShieldNettyTransport extends NettyTransport {
public static final String HOSTNAME_VERIFICATION_SETTING = "shield.ssl.hostname_verification";
public static final String HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING = "shield.ssl.hostname_verification.resolve_name";
private final SSLService sslService;
private final ServerSSLService serverSslService;
private final ClientSSLService clientSSLService;
private final @Nullable IPFilter authenticator;
private final boolean ssl;
@Inject
public ShieldNettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version,
@Nullable IPFilter authenticator, SSLService sslService) {
@Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, ClientSSLService clientSSLService) {
super(settings, threadPool, networkService, bigArrays, version);
this.authenticator = authenticator;
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
this.sslService = sslService;
this.serverSslService = serverSSLService;
this.clientSSLService = clientSSLService;
}
@Override
@ -69,9 +73,9 @@ public class ShieldNettyTransport extends NettyTransport {
if (profileSsl) {
SSLEngine serverEngine;
if (profileSettings.get("shield.truststore.path") != null) {
serverEngine = sslService.createSSLEngine(profileSettings.getByPrefix("shield."));
serverEngine = serverSslService.createSSLEngine(profileSettings.getByPrefix("shield."));
} else {
serverEngine = sslService.createSSLEngine();
serverEngine = serverSslService.createSSLEngine();
}
serverEngine.setUseClientMode(false);
serverEngine.setNeedClientAuth(profileSettings.getAsBoolean("shield.ssl.client.auth", settings.getAsBoolean("shield.transport.ssl.client.auth", true)));
@ -113,12 +117,16 @@ public class ShieldNettyTransport extends NettyTransport {
SSLEngine sslEngine;
if (settings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) {
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();
sslEngine = sslService.createClientSSLEngine(getHostname(inetSocketAddress), inetSocketAddress.getPort());
sslEngine = clientSSLService.createSSLEngine(ImmutableSettings.EMPTY, getHostname(inetSocketAddress), inetSocketAddress.getPort());
// By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification
// we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against
// man in the middle attacks for transport connections
SSLParameters parameters = new SSLParameters();
parameters.setEndpointIdentificationAlgorithm("HTTPS");
sslEngine.setSSLParameters(parameters);
} else {
sslEngine = sslService.createClientSSLEngine();
sslEngine = clientSSLService.createSSLEngine();
}
sslEngine.setUseClientMode(true);

View File

@ -14,7 +14,7 @@ import org.elasticsearch.shield.authc.ldap.LdapConnectionFactory;
import org.elasticsearch.shield.authc.ldap.LdapException;
import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.ldap.*;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.hamcrest.Matchers;
@ -44,7 +44,7 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
* verification tests since a re-established connection does not perform hostname verification.
*/
AbstractLdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
AbstractLdapSslSocketFactory.init(new ClientSSLService(ImmutableSettings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build()));

View File

@ -12,7 +12,7 @@ import org.elasticsearch.shield.authc.support.ldap.AbstractLdapSslSocketFactory;
import org.elasticsearch.shield.authc.support.ldap.ConnectionFactory;
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
import org.elasticsearch.shield.authc.support.ldap.SearchScope;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.support.NoOpLogger;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
@ -47,7 +47,7 @@ public class ActiveDirectoryGroupsResolverTests extends ElasticsearchTestCase {
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
* verification tests since a re-established connection does not perform hostname verification.
*/
AbstractLdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
AbstractLdapSslSocketFactory.init(new ClientSSLService(ImmutableSettings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build()));

View File

@ -11,7 +11,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.ldap.*;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.After;
@ -39,7 +39,7 @@ public class OpenLdapTests extends ElasticsearchTestCase {
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
* verification tests since a re-established connection does not perform hostname verification.
*/
AbstractLdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
AbstractLdapSslSocketFactory.init(new ClientSSLService(ImmutableSettings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build()));

View File

@ -12,7 +12,7 @@ import org.elasticsearch.shield.authc.support.ldap.AbstractLdapSslSocketFactory;
import org.elasticsearch.shield.authc.support.ldap.ConnectionFactory;
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
import org.elasticsearch.shield.authc.support.ldap.SearchScope;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.support.NoOpLogger;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
@ -46,7 +46,7 @@ public class SearchGroupsResolverTest extends ElasticsearchTestCase {
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
* verification tests since a re-established connection does not perform hostname verification.
*/
AbstractLdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
AbstractLdapSslSocketFactory.init(new ClientSSLService(ImmutableSettings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build()));

View File

@ -12,7 +12,7 @@ import org.elasticsearch.shield.authc.active_directory.ActiveDirectoryFactoryTes
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapSslSocketFactory;
import org.elasticsearch.shield.authc.support.ldap.ConnectionFactory;
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.support.NoOpLogger;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
@ -31,21 +31,21 @@ import java.util.List;
import static org.hamcrest.Matchers.*;
@Network
public class UserAttributeGroupsResolverTest extends ElasticsearchTestCase {
public class UserAttributeGroupsResolverTests extends ElasticsearchTestCase {
public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
private InitialDirContext ldapContext;
@Before
public void setUp() throws Exception {
super.setUp();
Path keystore = Paths.get(UserAttributeGroupsResolverTest.class.getResource("../support/ldap/ldaptrust.jks").toURI()).toAbsolutePath();
Path keystore = Paths.get(UserAttributeGroupsResolverTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).toAbsolutePath();
/*
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
* verification tests since a re-established connection does not perform hostname verification.
*/
AbstractLdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
AbstractLdapSslSocketFactory.init(new ClientSSLService(ImmutableSettings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build()));

View File

@ -0,0 +1,210 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.Before;
import org.junit.Test;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSessionContext;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
public class ClientSSLServiceTests extends ElasticsearchTestCase {
Path testclientStore;
@Before
public void setup() throws Exception {
testclientStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
}
@Test(expected = ElasticsearchSSLException.class)
public void testThatInvalidProtocolThrowsException() throws Exception {
new ClientSSLService(settingsBuilder()
.put("shield.ssl.protocol", "non-existing")
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.put("shield.ssl.truststore.path", testclientStore)
.put("shield.ssl.truststore.password", "testclient")
.build()).createSSLEngine();
}
@Test
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
Path testnodeStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI());
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
ImmutableSettings.Builder settingsBuilder = settingsBuilder()
.put("truststore.path", testnodeStore)
.put("truststore.password", "testnode");
SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(settingsBuilder.build());
assertThat(sslEngineWithTruststore, is(not(nullValue())));
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngineWithTruststore, is(not(sameInstance(sslEngine))));
}
@Test
public void testThatSslContextCachingWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLContext sslContext = sslService.sslContext();
SSLContext cachedSslContext = sslService.sslContext();
assertThat(sslContext, is(sameInstance(cachedSslContext)));
}
@Test
public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception {
Path differentPasswordsStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks").toURI());
new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.keystore.key_password", "testnode1")
.build()).createSSLEngine();
}
@Test(expected = ElasticsearchSSLException.class)
public void testIncorrectKeyPasswordThrowsException() throws Exception {
Path differentPasswordsStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks").toURI());
new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.build()).createSSLEngine();
}
@Test
public void testThatSSLv3IsNotEnabled() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLEngine engine = sslService.createSSLEngine();
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
}
@Test
public void testThatSSLSessionCacheHasDefaultLimits() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(1000));
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
}
@Test
public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.put("shield.ssl.session.cache_size", "300")
.put("shield.ssl.session.cache_timeout", "600s")
.build());
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(300));
assertThat(context.getSessionTimeout(), equalTo(600));
}
@Test
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(ImmutableSettings.EMPTY);
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testclientStore)
.put("shield.ssl.truststore.password", "testclient")
.build());
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
public void testThatCreateSSLEngineWithOnlyKeystoreWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
@Network
public void testThatSSLContextWithoutSettingsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(ImmutableSettings.EMPTY);
SSLContext sslContext = sslService.sslContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
// This will result in a SSLHandshakeException if the SSLContext does not trust the CA, but the default
// truststore trusts all common public CAs so the handshake will succeed
client.execute(new HttpGet("https://www.elasticsearch.com/"));
}
}
@Test
@Network
public void testThatSSLContextWithKeystoreDoesNotTrustAllPublicCAs() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build());
SSLContext sslContext = sslService.sslContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
// This will result in a SSLHandshakeException because the truststore is the testnodestore, which doesn't
// trust any public CAs
client.execute(new HttpGet("https://www.elasticsearch.com/"));
fail("A SSLHandshakeException should have been thrown here");
} catch (Exception e) {
assertThat(e, instanceOf(SSLHandshakeException.class));
}
}
@Test(expected = ShieldSettingsException.class)
public void testThatTruststorePasswordIsRequired() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testclientStore)
.build());
sslService.sslContext();
}
@Test(expected = ShieldSettingsException.class)
public void testThatKeystorePasswordIsRequired() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.build());
sslService.sslContext();
}
}

View File

@ -0,0 +1,210 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.shield.ssl.AbstractSSLService.SSLSettings;
import org.junit.Test;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
public class SSLSettingsTests extends ElasticsearchTestCase {
@Test
public void testThatSSLSettingsWithEmptySettingsHaveCorrectDefaults() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, ImmutableSettings.EMPTY);
assertThat(sslSettings.keyStorePath, is(nullValue()));
assertThat(sslSettings.keyStorePassword, is(nullValue()));
assertThat(sslSettings.keyPassword, is(nullValue()));
assertThat(sslSettings.keyStoreAlgorithm, is(equalTo(KeyManagerFactory.getDefaultAlgorithm())));
assertThat(sslSettings.sessionCacheSize, is(equalTo(AbstractSSLService.DEFAULT_SESSION_CACHE_SIZE)));
assertThat(sslSettings.sessionCacheTimeout, is(equalTo(AbstractSSLService.DEFAULT_SESSION_CACHE_TIMEOUT)));
assertThat(sslSettings.sslProtocol, is(equalTo(AbstractSSLService.DEFAULT_PROTOCOL)));
assertThat(sslSettings.trustStoreAlgorithm, is(equalTo(TrustManagerFactory.getDefaultAlgorithm())));
assertThat(sslSettings.trustStorePassword, is(nullValue()));
assertThat(sslSettings.trustStorePath, is(nullValue()));
}
@Test
public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() {
Settings settings = settingsBuilder()
.put("keystore.path", "path")
.put("keystore.password", "password")
.build();
// Pass settings in as component settings
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settings);
assertThat(sslSettings.keyStorePath, is(equalTo("path")));
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
assertThat(sslSettings.trustStorePath, is(equalTo(sslSettings.keyStorePath)));
assertThat(sslSettings.trustStorePassword, is(equalTo(sslSettings.keyStorePassword)));
// Pass settings in as profile settings
SSLSettings sslSettings1 = new SSLSettings(settings, ImmutableSettings.EMPTY);
assertThat(sslSettings1.keyStorePath, is(equalTo("path")));
assertThat(sslSettings1.keyStorePassword, is(equalTo("password")));
assertThat(sslSettings1.trustStorePath, is(equalTo(sslSettings1.keyStorePath)));
assertThat(sslSettings1.trustStorePassword, is(equalTo(sslSettings1.keyStorePassword)));
}
@Test
public void testThatKeystorePasswordIsDefaultKeyPassword() {
Settings settings = settingsBuilder()
.put("keystore.password", "password")
.build();
// Pass settings in as component settings
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settings);
assertThat(sslSettings.keyPassword, is(equalTo(sslSettings.keyStorePassword)));
// Pass settings in as profile settings
SSLSettings sslSettings1 = new SSLSettings(settings, ImmutableSettings.EMPTY);
assertThat(sslSettings1.keyPassword, is(equalTo(sslSettings1.keyStorePassword)));
}
@Test
public void testThatKeyPasswordCanBeSet() {
Settings settings = settingsBuilder()
.put("keystore.password", "password")
.put("keystore.key_password", "key")
.build();
// Pass settings in as component settings
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settings);
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
assertThat(sslSettings.keyPassword, is(equalTo("key")));
// Pass settings in as profile settings
SSLSettings sslSettings1 = new SSLSettings(settings, ImmutableSettings.EMPTY);
assertThat(sslSettings1.keyStorePassword, is(equalTo("password")));
assertThat(sslSettings1.keyPassword, is(equalTo("key")));
}
@Test
public void testThatProfileSettingsOverrideComponentSettings() {
Settings profileSettings = settingsBuilder()
.put("keystore.path", "path")
.put("keystore.password", "password")
.put("keystore.key_password", "key")
.put("keystore.algorithm", "algo")
.put("truststore.path", "trust path")
.put("truststore.password", "password for trust")
.put("truststore.algorithm", "trusted")
.put("protocol", "ssl")
.put("session.cache_size", "3")
.put("session.cache_timeout", "10m")
.build();
Settings componentSettings = settingsBuilder()
.put("keystore.path", "comp path")
.put("keystore.password", "comp password")
.put("keystore.key_password", "comp key")
.put("keystore.algorithm", "comp algo")
.put("truststore.path", "comp trust path")
.put("truststore.password", "comp password for trust")
.put("truststore.algorithm", "comp trusted")
.put("protocol", "tls")
.put("session.cache_size", "7")
.put("session.cache_timeout", "20m")
.build();
SSLSettings sslSettings = new SSLSettings(profileSettings, componentSettings);
assertThat(sslSettings.keyStorePath, is(equalTo("path")));
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
assertThat(sslSettings.keyPassword, is(equalTo("key")));
assertThat(sslSettings.keyStoreAlgorithm, is(equalTo("algo")));
assertThat(sslSettings.trustStorePath, is(equalTo("trust path")));
assertThat(sslSettings.trustStorePassword, is(equalTo("password for trust")));
assertThat(sslSettings.trustStoreAlgorithm, is(equalTo("trusted")));
assertThat(sslSettings.sslProtocol, is(equalTo("ssl")));
assertThat(sslSettings.sessionCacheSize, is(equalTo(3)));
assertThat(sslSettings.sessionCacheTimeout, is(equalTo(TimeValue.parseTimeValue("10m", null))));
}
@Test
public void testThatEmptySettingsAreEqual() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, ImmutableSettings.EMPTY);
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, ImmutableSettings.EMPTY);
assertThat(sslSettings.equals(sslSettings1), is(equalTo(true)));
assertThat(sslSettings1.equals(sslSettings), is(equalTo(true)));
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
}
@Test
public void testThatSettingsWithDifferentKeystoresAreNotEqual() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("keystore.path", "path").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("keystore.path", "path1").build());
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
}
@Test
public void testThatSettingsWithDifferentProtocolsAreNotEqual() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("protocol", "ssl").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("protocol", "tls").build());
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
}
@Test
public void testThatSettingsWithDifferentTruststoresAreNotEqual() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("truststore.path", "/trust").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("truststore.path", "/truststore").build());
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
}
@Test
public void testThatEmptySettingsHaveSameHashCode() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, ImmutableSettings.EMPTY);
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, ImmutableSettings.EMPTY);
assertThat(sslSettings.hashCode(), is(equalTo(sslSettings1.hashCode())));
}
@Test
public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("keystore.path", "path").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("keystore.path", "path1").build());
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
}
@Test
public void testThatSettingsWithDifferentProtocolsHaveDifferentHashCode() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("protocol", "ssl").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("protocol", "tls").build());
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
}
@Test
public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() {
SSLSettings sslSettings = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("truststore.path", "/trust").build());
SSLSettings sslSettings1 = new SSLSettings(ImmutableSettings.EMPTY, settingsBuilder()
.put("truststore.path", "/truststore").build());
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
}
}

View File

@ -5,19 +5,15 @@
*/
package org.elasticsearch.shield.ssl;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.junit.Before;
import org.junit.Test;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSessionContext;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -26,7 +22,7 @@ import java.util.Arrays;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
public class SSLServiceTests extends ElasticsearchTestCase {
public class ServerSSLServiceTests extends ElasticsearchTestCase {
Path testnodeStore;
@ -37,7 +33,7 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test(expected = ElasticsearchSSLException.class)
public void testThatInvalidProtocolThrowsException() throws Exception {
new SSLService(settingsBuilder()
new ServerSSLService(settingsBuilder()
.put("shield.ssl.protocol", "non-existing")
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
@ -50,7 +46,7 @@ public class SSLServiceTests extends ElasticsearchTestCase {
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
Path testClientStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
@ -68,13 +64,13 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test
public void testThatSslContextCachingWorks() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
SSLContext sslContext = sslService.getSslContext();
SSLContext cachedSslContext = sslService.getSslContext();
SSLContext sslContext = sslService.sslContext();
SSLContext cachedSslContext = sslService.sslContext();
assertThat(sslContext, is(sameInstance(cachedSslContext)));
}
@ -82,7 +78,7 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test
public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception {
Path differentPasswordsStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks").toURI());
new SSLService(settingsBuilder()
new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.keystore.key_password", "testnode1")
@ -92,7 +88,7 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test(expected = ElasticsearchSSLException.class)
public void testIncorrectKeyPasswordThrowsException() throws Exception {
Path differentPasswordsStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks").toURI());
new SSLService(settingsBuilder()
new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.build()).createSSLEngine();
@ -100,7 +96,7 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test
public void testThatSSLv3IsNotEnabled() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
@ -110,84 +106,59 @@ public class SSLServiceTests extends ElasticsearchTestCase {
@Test
public void testThatSSLSessionCacheHasDefaultLimits() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
SSLSessionContext context = sslService.getSslContext().getServerSessionContext();
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(1000));
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
}
@Test
public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.session.cache_size", "300")
.put("shield.ssl.session.cache_timeout", "600s")
.build());
SSLSessionContext context = sslService.getSslContext().getServerSessionContext();
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(300));
assertThat(context.getSessionTimeout(), equalTo(600));
}
@Test
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
SSLService sslService = new SSLService(ImmutableSettings.EMPTY);
SSLEngine sslEngine = sslService.createClientSSLEngine();
assertThat(sslEngine, notNullValue());
@Test(expected = ShieldSettingsException.class)
public void testThatCreateSSLEngineWithoutAnySettingsDoesNotWork() throws Exception {
ServerSSLService sslService = new ServerSSLService(ImmutableSettings.EMPTY);
sslService.createSSLEngine();
}
@Test
public void testThatCreateClientSSLEngineWithOnlyTruststoreWorks() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
@Test(expected = ShieldSettingsException.class)
public void testThatCreateSSLEngineWithOnlyTruststoreDoesNotWork() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testnodeStore)
.put("shield.ssl.truststore.password", "testnode")
.build());
SSLEngine sslEngine = sslService.createClientSSLEngine();
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
public void testThatCreateClientSSLEngineWithOnlyKeystoreWorks() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
@Test(expected = ShieldSettingsException.class)
public void testThatTruststorePasswordIsRequired() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.truststore.path", testnodeStore)
.build());
SSLEngine sslEngine = sslService.createClientSSLEngine();
assertThat(sslEngine, notNullValue());
sslService.sslContext();
}
@Test
@Network
public void testThatClientSSLContextWithoutSettingsWorks() throws Exception {
SSLService sslService = new SSLService(ImmutableSettings.EMPTY);
SSLContext sslContext = sslService.getClientSSLContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
// This will result in a SSLHandshakeException if the SSLContext does not trust the CA, but the default
// truststore trusts all common public CAs so the handshake will succeed
client.execute(new HttpGet("https://www.elasticsearch.com/"));
}
}
@Test
@Network
public void testThatClientSSLContextWithKeystoreDoesNotTrustAllPublicCAs() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
@Test(expected = ShieldSettingsException.class)
public void testThatKeystorePasswordIsRequired() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
SSLContext sslContext = sslService.getSslContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
// This will result in a SSLHandshakeException because the truststore is the testnodestore, which doesn't
// trust any public CAs
client.execute(new HttpGet("https://www.elasticsearch.com/"));
fail("A SSLHandshakeException should have been thrown here");
} catch (Exception e) {
assertThat(e, instanceOf(SSLHandshakeException.class));
}
sslService.sslContext();
}
}

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.netty.channel.*;
import org.elasticsearch.common.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.elasticsearch.common.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.elasticsearch.common.netty.handler.ssl.SslHandler;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.After;
import org.junit.Before;
@ -64,12 +64,12 @@ public class HandshakeWaitingHandlerTests extends ElasticsearchTestCase {
@Before
public void setup() throws Exception {
SSLService sslService = new SSLService(settingsBuilder()
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", Paths.get(HandshakeWaitingHandlerTests.class.getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI()))
.put("shield.ssl.keystore.password", "testnode")
.build());
sslContext = sslService.getSslContext();
sslContext = sslService.sslContext();
serverBootstrap = new ServerBootstrap(new NioServerSocketChannelFactory());
serverBootstrap.setPipelineFactory(getServerFactory());
@ -231,8 +231,10 @@ public class HandshakeWaitingHandlerTests extends ElasticsearchTestCase {
// in the test
ChannelFuture handshakeFuture = null;
for (int i = 0; i < 100; i++) {
if (handshakeFuture == null) {
handshakeFuture = channel.getPipeline().get(SslHandler.class).handshake();
}
channel.write(buffer);
handshakeFuture = channel.getPipeline().get(SslHandler.class).handshake();
}
return handshakeFuture;

View File

@ -13,7 +13,8 @@ import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.netty.NettyTransport;
@ -30,21 +31,24 @@ import static org.hamcrest.Matchers.*;
public class ShieldNettyTransportTests extends ElasticsearchTestCase {
private SSLService sslService;
private ServerSSLService serverSSLService;
private ClientSSLService clientSSLService;
@Before
public void createSSLService() throws Exception {
Path testnodeStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI());
sslService = new SSLService(settingsBuilder()
Settings settings = settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
.build();
serverSSLService = new ServerSSLService(settings);
clientSSLService = new ClientSSLService(settings);
}
@Test
public void testThatSSLCanBeDisabledByProfile() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", true).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, sslService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.builder().put("shield.ssl", false).build());
assertThat(factory.getPipeline().get(SslHandler.class), nullValue());
@ -53,7 +57,7 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
@Test
public void testThatSSLCanBeEnabledByProfile() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", false).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, sslService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.builder().put("shield.ssl", true).build());
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());
@ -62,7 +66,7 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
@Test
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", true).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, sslService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.EMPTY);
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.test.ShieldIntegrationTest;
import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
@ -73,10 +73,10 @@ public class SslClientAuthTests extends ShieldIntegrationTest {
@Test
public void testThatHttpWorksWithSslClientAuth() throws IOException {
Settings settings = settingsBuilder().put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient")).build();
SSLService sslService = new SSLService(settings);
ClientSSLService sslService = new ClientSSLService(settings);
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
sslService.getSslContext(),
sslService.sslContext(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();