diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 355583eeaa3..ca73c3c8174 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -110,10 +110,8 @@ import org.elasticsearch.xpack.security.rest.action.user.RestChangePasswordActio import org.elasticsearch.xpack.security.rest.action.user.RestDeleteUserAction; import org.elasticsearch.xpack.security.rest.action.user.RestGetUsersAction; import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration; import org.elasticsearch.xpack.security.ssl.SSLConfigurationReloader; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.support.OptionalSettings; import org.elasticsearch.xpack.security.transport.SecurityClientTransportService; import org.elasticsearch.xpack.security.transport.SecurityServerTransportService; @@ -182,8 +180,7 @@ public class Security implements ActionPlugin, IngestPlugin { modules.add(new SecurityTransportModule(settings)); modules.add(b -> { // for transport client we still must inject these ssl classes with guice - b.bind(ServerSSLService.class).toProvider(Providers.of(null)); - b.bind(ClientSSLService.class).toInstance(new ClientSSLService(settings, null, new SSLConfiguration.Global(settings))); + b.bind(SSLService.class).toInstance(new SSLService(settings, null)); }); return modules; @@ -228,15 +225,10 @@ public class Security implements ActionPlugin, IngestPlugin { final SecurityContext securityContext = new SecurityContext(settings, threadPool, cryptoService); components.add(securityContext); - final SSLConfiguration.Global globalSslConfig = new SSLConfiguration.Global(settings); - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, globalSslConfig); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, globalSslConfig); - // just create the reloader as it will register itself as a listener to the ssl service and nothing else depends on it - // IMPORTANT: if the reloader construction is moved to later, then it needs to be updated to ensure any SSLContexts that have been - // loaded by the services are also monitored by the reloader! - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); - components.add(clientSSLService); - components.add(serverSSLService); + final SSLService sslService = new SSLService(settings, env); + // just create the reloader as it will pull all of the loaded ssl configurations and start watching them + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService); + components.add(sslService); // realms construction final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, threadPool); @@ -245,8 +237,8 @@ public class Security implements ActionPlugin, IngestPlugin { realmFactories.put(FileRealm.TYPE, config -> new FileRealm(config, resourceWatcherService)); realmFactories.put(NativeRealm.TYPE, config -> new NativeRealm(config, nativeUsersStore)); realmFactories.put(ActiveDirectoryRealm.TYPE, - config -> new ActiveDirectoryRealm(config, resourceWatcherService, clientSSLService)); - realmFactories.put(LdapRealm.TYPE, config -> new LdapRealm(config, resourceWatcherService, clientSSLService)); + config -> new ActiveDirectoryRealm(config, resourceWatcherService, sslService)); + realmFactories.put(LdapRealm.TYPE, config -> new LdapRealm(config, resourceWatcherService, sslService)); realmFactories.put(PkiRealm.TYPE, config -> new PkiRealm(config, resourceWatcherService)); for (XPackExtension extension : extensions) { Map newRealms = extension.getRealms(); @@ -379,7 +371,7 @@ public class Security implements ActionPlugin, IngestPlugin { settingsList.add(USER_SETTING); // SSL settings - SSLConfiguration.Global.addSettings(settingsList); + SSLService.addSettings(settingsList); // transport settings SecurityNetty3Transport.addSettings(settingsList); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryRealm.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryRealm.java index 91ac8cd2993..06d6415a660 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryRealm.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryRealm.java @@ -10,7 +10,7 @@ import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.ldap.support.AbstractLdapRealm; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.DnRoleMapper; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; /** * @@ -19,8 +19,8 @@ public class ActiveDirectoryRealm extends AbstractLdapRealm { public static final String TYPE = "active_directory"; - public ActiveDirectoryRealm(RealmConfig config, ResourceWatcherService watcherService, ClientSSLService clientSSLService) { - this(config, new ActiveDirectorySessionFactory(config, clientSSLService), + public ActiveDirectoryRealm(RealmConfig config, ResourceWatcherService watcherService, SSLService sslService) { + this(config, new ActiveDirectorySessionFactory(config, sslService), new DnRoleMapper(TYPE, config, watcherService, null)); } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactory.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactory.java index b0231319eb9..c769463107d 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactory.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactory.java @@ -23,7 +23,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import java.util.concurrent.ExecutionException; @@ -54,7 +54,7 @@ public class ActiveDirectorySessionFactory extends SessionFactory { private final DownLevelADAuthenticator downLevelADAuthenticator; private final UpnADAuthenticator upnADAuthenticator; - public ActiveDirectorySessionFactory(RealmConfig config, ClientSSLService sslService) { + public ActiveDirectorySessionFactory(RealmConfig config, SSLService sslService) { super(config, sslService); Settings settings = config.settings(); domainName = settings.get(AD_DOMAIN_NAME_SETTING); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeRealmMigrateTool.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeRealmMigrateTool.java index 517791211c7..b8066d220f5 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeRealmMigrateTool.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeRealmMigrateTool.java @@ -29,8 +29,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authz.RoleDescriptor; import org.elasticsearch.xpack.security.authz.store.FileRolesStore; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration; +import org.elasticsearch.xpack.security.ssl.SSLService; import java.io.BufferedReader; import java.io.IOException; @@ -134,8 +133,7 @@ public class ESNativeRealmMigrateTool extends MultiCommand { // If using SSL, need a custom service because it's likely a self-signed certificate if ("https".equalsIgnoreCase(uri.getScheme())) { Settings sslSettings = settings.getByPrefix(setting("http.ssl.")); - SSLConfiguration.Global globalConfig = new SSLConfiguration.Global(settings); - final ClientSSLService sslService = new ClientSSLService(sslSettings, env, globalConfig); + final SSLService sslService = new SSLService(settings, env); final HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection(); AccessController.doPrivileged(new PrivilegedAction() { @Override diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java index e2de7894095..9b2b4b71753 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealm.java @@ -15,7 +15,7 @@ import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.ldap.support.AbstractLdapRealm; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.DnRoleMapper; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; /** @@ -25,8 +25,8 @@ public class LdapRealm extends AbstractLdapRealm { public static final String TYPE = "ldap"; - public LdapRealm(RealmConfig config, ResourceWatcherService watcherService, ClientSSLService clientSSLService) { - this(config, sessionFactory(config, clientSSLService), new DnRoleMapper(TYPE, config, watcherService, null)); + public LdapRealm(RealmConfig config, ResourceWatcherService watcherService, SSLService sslService) { + this(config, sessionFactory(config, sslService), new DnRoleMapper(TYPE, config, watcherService, null)); } // pkg private for testing @@ -34,7 +34,7 @@ public class LdapRealm extends AbstractLdapRealm { super(TYPE, config, sessionFactory, roleMapper); } - static SessionFactory sessionFactory(RealmConfig config, ClientSSLService clientSSLService) { + static SessionFactory sessionFactory(RealmConfig config, SSLService sslService) { Settings searchSettings = userSearchSettings(config); try { if (!searchSettings.names().isEmpty()) { @@ -43,9 +43,9 @@ public class LdapRealm extends AbstractLdapRealm { "Please remove the settings for the mode you do not wish to use. For more details refer to the ldap " + "authentication section of the X-Pack guide."); } - return new LdapUserSearchSessionFactory(config, clientSSLService); + return new LdapUserSearchSessionFactory(config, sslService); } - return new LdapSessionFactory(config, clientSSLService); + return new LdapSessionFactory(config, sslService); } catch (LDAPException e) { throw new ElasticsearchException("failed to create realm [{}/{}]", e, LdapRealm.TYPE, config.name()); } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java index 5ffd2a52304..4181b339232 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapSessionFactory.java @@ -13,7 +13,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import java.text.MessageFormat; import java.util.Locale; @@ -33,7 +33,7 @@ public class LdapSessionFactory extends SessionFactory { private final String[] userDnTemplates; private final GroupsResolver groupResolver; - public LdapSessionFactory(RealmConfig config, ClientSSLService sslService) { + public LdapSessionFactory(RealmConfig config, SSLService sslService) { super(config, sslService); Settings settings = config.settings(); userDnTemplates = settings.getAsArray(USER_DN_TEMPLATES_SETTING); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java index 77ceefcc7e3..4ca53662002 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactory.java @@ -24,7 +24,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.support.Exceptions; import java.util.Locale; @@ -49,7 +49,7 @@ class LdapUserSearchSessionFactory extends SessionFactory { private final LDAPConnectionPool connectionPool; - LdapUserSearchSessionFactory(RealmConfig config, ClientSSLService sslService) throws LDAPException { + LdapUserSearchSessionFactory(RealmConfig config, SSLService sslService) throws LDAPException { super(config, sslService); Settings settings = config.settings(); userSearchBaseDn = settings.get("user_search.base_dn"); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java index cd8799486b7..fede5cd7d02 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java @@ -16,7 +16,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import javax.net.SocketFactory; import java.util.regex.Pattern; @@ -50,12 +50,12 @@ public abstract class SessionFactory { protected final ESLogger logger; protected final RealmConfig config; protected final TimeValue timeout; - protected final ClientSSLService sslService; + protected final SSLService sslService; protected final ServerSet serverSet; protected final boolean sslUsed; - protected SessionFactory(RealmConfig config, ClientSSLService sslService) { + protected SessionFactory(RealmConfig config, SSLService sslService) { this.config = config; this.logger = config.logger(getClass()); TimeValue searchTimeout = config.settings().getAsTime(TIMEOUT_LDAP_SETTING, TIMEOUT_DEFAULT); @@ -142,7 +142,7 @@ public abstract class SessionFactory { return null; } - protected ServerSet serverSet(Settings settings, ClientSSLService clientSSLService, LDAPServers ldapServers) { + protected ServerSet serverSet(Settings settings, SSLService clientSSLService, LDAPServers ldapServers) { SocketFactory socketFactory = null; if (ldapServers.ssl()) { socketFactory = clientSSLService.sslSocketFactory(settings.getByPrefix("ssl.")); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/AbstractSSLService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/AbstractSSLService.java deleted file mode 100644 index 80595be17d5..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/AbstractSSLService.java +++ /dev/null @@ -1,307 +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.xpack.security.ssl; - -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.component.AbstractComponent; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Custom; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 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 { - - private final SSLContextCacheLoader cacheLoader = new SSLContextCacheLoader(); - private final ConcurrentHashMap sslContexts = new ConcurrentHashMap<>(); - - protected final SSLConfiguration globalSSLConfiguration; - protected final Environment env; - - private Listener listener = Listener.NOOP; - - AbstractSSLService(Settings settings, Environment environment, Global globalSSLConfiguration) { - super(settings); - this.env = environment; - this.globalSSLConfiguration = globalSSLConfiguration; - } - - public String[] supportedProtocols() { - return globalSSLConfiguration.supportedProtocols().toArray(Strings.EMPTY_ARRAY); - } - - public String[] ciphers() { - return globalSSLConfiguration.ciphers().toArray(Strings.EMPTY_ARRAY); - } - - public SSLSocketFactory sslSocketFactory(Settings settings) { - return sslSocketFactory(sslContext(settings)); - } - - protected SSLSocketFactory sslSocketFactory(SSLContext sslContext) { - SSLSocketFactory socketFactory = sslContext.getSocketFactory(); - return new SecuritySSLSocketFactory(socketFactory, supportedProtocols(), - supportedCiphers(socketFactory.getSupportedCipherSuites(), ciphers(), false)); - } - - public SSLEngine createSSLEngine() { - return createSSLEngine(globalSSLConfiguration, null, -1); - } - - public SSLEngine createSSLEngine(Settings settings) { - return createSSLEngine(settings, null, -1); - } - - public SSLEngine createSSLEngine(Settings settings, String host, int port) { - if (settings.isEmpty()) { - return createSSLEngine(globalSSLConfiguration, host, port); - } - return createSSLEngine(sslConfiguration(settings), host, port); - } - - public SSLEngine createSSLEngine(SSLConfiguration configuration, String host, int port) { - return createSSLEngine(sslContext(configuration), - configuration.ciphers().toArray(Strings.EMPTY_ARRAY), - configuration.supportedProtocols().toArray(Strings.EMPTY_ARRAY), - host, port); - } - - public SSLContext sslContext() { - return sslContext(globalSSLConfiguration); - } - - public SSLContext sslContext(Settings settings) { - if (settings.isEmpty()) { - return sslContext(); - } - - SSLConfiguration sslConfiguration = sslConfiguration(settings); - return sslContext(sslConfiguration); - } - - protected SSLContext sslContext(SSLConfiguration sslConfiguration) { - return sslContexts.computeIfAbsent(sslConfiguration, cacheLoader::load); - } - - protected SSLConfiguration sslConfiguration(Settings customSettings) { - return new Custom(customSettings, globalSSLConfiguration); - } - - protected abstract void validateSSLConfiguration(SSLConfiguration configuration); - - SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) { - SSLEngine sslEngine = sslContext.createSSLEngine(host, port); - try { - sslEngine.setEnabledCipherSuites(supportedCiphers(sslEngine.getSupportedCipherSuites(), ciphers, false)); - } catch (ElasticsearchException e) { - throw e; - } catch (Exception e) { - throw new IllegalArgumentException("failed loading cipher suites [" + Arrays.asList(ciphers) + "]", e); - } - - try { - sslEngine.setEnabledProtocols(supportedProtocols); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("failed setting supported protocols [" + Arrays.asList(supportedProtocols) + "]", e); - } - return sslEngine; - } - - String[] supportedCiphers(String[] supportedCiphers, String[] requestedCiphers, boolean log) { - List requestedCiphersList = new ArrayList<>(requestedCiphers.length); - List unsupportedCiphers = new LinkedList<>(); - boolean found; - for (String requestedCipher : requestedCiphers) { - found = false; - for (String supportedCipher : supportedCiphers) { - if (supportedCipher.equals(requestedCipher)) { - found = true; - requestedCiphersList.add(requestedCipher); - break; - } - } - - if (!found) { - unsupportedCiphers.add(requestedCipher); - } - } - - if (requestedCiphersList.isEmpty()) { - throw new IllegalArgumentException("none of the ciphers " + Arrays.asList(requestedCiphers) + " are supported by this JVM"); - } - - if (log && !unsupportedCiphers.isEmpty()) { - logger.error("unsupported ciphers [{}] were requested but cannot be used in this JVM, however there are supported ciphers " + - "that will be used [{}]. If you are trying to use ciphers with a key length greater than 128 bits on an Oracle JVM, " + - "you will need to install the unlimited strength JCE policy files.", unsupportedCiphers, requestedCiphersList); - } - - return requestedCiphersList.toArray(new String[requestedCiphersList.size()]); - } - - /** - * Sets the listener to the value provided. Must not be {@code null} - */ - void setListener(Listener listener) { - this.listener = Objects.requireNonNull(listener); - } - - /** - * Returns the existing {@link SSLContext} for the configuration or {@code null} - */ - SSLContext getSSLContext(SSLConfiguration sslConfiguration) { - return sslContexts.get(sslConfiguration); - } - - /** - * Accessor to the loaded ssl configuration objects at the current point in time. This is useful for testing - */ - Collection getLoadedSSLConfigurations() { - return Collections.unmodifiableSet(new HashSet<>(sslContexts.keySet())); - } - - private class SSLContextCacheLoader { - - public SSLContext load(SSLConfiguration sslConfiguration) { - validateSSLConfiguration(sslConfiguration); - if (logger.isDebugEnabled()) { - logger.debug("using ssl settings [{}]", sslConfiguration); - } - - TrustManager[] trustManagers = sslConfiguration.trustConfig().trustManagers(env); - KeyManager[] keyManagers = sslConfiguration.keyConfig().keyManagers(env); - SSLContext sslContext = createSslContext(keyManagers, trustManagers, sslConfiguration.protocol(), - sslConfiguration.sessionCacheSize(), sslConfiguration.sessionCacheTimeout()); - - // check the supported ciphers and log them here - supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), - sslConfiguration.ciphers().toArray(Strings.EMPTY_ARRAY), true); - listener.onSSLContextLoaded(sslConfiguration); - return sslContext; - } - - 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(Math.toIntExact(sessionCacheTimeout.seconds())); - return sslContext; - } catch (Exception e) { - throw new ElasticsearchException("failed to initialize the SSLContext", e); - } - } - } - - /** - * This socket factory set the protocols and ciphers on each SSLSocket after it is created - */ - static class SecuritySSLSocketFactory extends SSLSocketFactory { - - private final SSLSocketFactory delegate; - private final String[] supportedProtocols; - private final String[] ciphers; - - SecuritySSLSocketFactory(SSLSocketFactory delegate, String[] supportedProtocols, String[] ciphers) { - this.delegate = delegate; - this.supportedProtocols = supportedProtocols; - this.ciphers = ciphers; - } - - @Override - public String[] getDefaultCipherSuites() { - return ciphers; - } - - @Override - public String[] getSupportedCipherSuites() { - return delegate.getSupportedCipherSuites(); - } - - @Override - public Socket createSocket() throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(); - configureSSLSocket(sslSocket); - return sslSocket; - } - - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(socket, host, port, autoClose); - configureSSLSocket(sslSocket); - return sslSocket; - } - - @Override - public Socket createSocket(String host, int port) throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port); - configureSSLSocket(sslSocket); - return sslSocket; - } - - @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort); - configureSSLSocket(sslSocket); - return sslSocket; - } - - @Override - public Socket createSocket(InetAddress host, int port) throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port); - configureSSLSocket(sslSocket); - return sslSocket; - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { - SSLSocket sslSocket = (SSLSocket) delegate.createSocket(address, port, localAddress, localPort); - configureSSLSocket(sslSocket); - return sslSocket; - } - - private void configureSSLSocket(SSLSocket socket) { - socket.setEnabledProtocols(supportedProtocols); - socket.setEnabledCipherSuites(ciphers); - } - } - - interface Listener { - /** - * Called after a new SSLContext has been created - * @param sslConfiguration the configuration used to create the SSLContext - */ - void onSSLContextLoaded(SSLConfiguration sslConfiguration); - - Listener NOOP = (s) -> {}; - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ClientSSLService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ClientSSLService.java deleted file mode 100644 index 8805703c1f1..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ClientSSLService.java +++ /dev/null @@ -1,23 +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.xpack.security.ssl; - -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; - -public class ClientSSLService extends AbstractSSLService { - - public ClientSSLService(Settings settings, Environment env, Global globalSSLConfiguration) { - super(settings, env, globalSSLConfiguration); - } - - @Override - protected void validateSSLConfiguration(SSLConfiguration sslConfiguration) { - sslConfiguration.keyConfig().validate(); - sslConfiguration.trustConfig().validate(); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java index 31c46bc312a..baef56615e6 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java @@ -21,15 +21,13 @@ import java.util.List; abstract class KeyConfig extends TrustConfig { - private X509ExtendedKeyManager[] keyManagers = null; - KeyConfig(boolean includeSystem) { super(includeSystem); } static final KeyConfig NONE = new KeyConfig(false) { @Override - X509ExtendedKeyManager loadKeyManager(@Nullable Environment environment) { + X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { return null; } @@ -53,97 +51,5 @@ abstract class KeyConfig extends TrustConfig { } }; - final synchronized X509ExtendedKeyManager[] keyManagers(@Nullable Environment environment) { - if (keyManagers == null) { - X509ExtendedKeyManager keyManager = loadKeyManager(environment); - setKeyManagers(keyManager); - } - return keyManagers; - } - - @Override - synchronized void reload(@Nullable Environment environment) { - if (trustManagers == null) { - // trust managers were never initialized... do it lazily! - X509ExtendedKeyManager loadedKeyManager = loadKeyManager(environment); - setKeyManagers(loadedKeyManager); - return; - } - - X509ExtendedTrustManager loadedTrustManager = loadAndMergeIfNecessary(environment); - X509ExtendedKeyManager loadedKeyManager = loadKeyManager(environment); - setTrustManagers(loadedTrustManager); - setKeyManagers(loadedKeyManager); - } - - final synchronized void setKeyManagers(X509ExtendedKeyManager loadedKeyManager) { - if (loadedKeyManager == null) { - this.keyManagers = new X509ExtendedKeyManager[0]; - } else if (this.keyManagers == null || this.keyManagers.length == 0) { - this.keyManagers = new X509ExtendedKeyManager[] { new ReloadableX509KeyManager(loadedKeyManager) }; - } else { - assert this.keyManagers[0] instanceof ReloadableX509KeyManager; - ((ReloadableX509KeyManager)this.keyManagers[0]).setKeyManager(loadedKeyManager); - } - } - - abstract X509ExtendedKeyManager loadKeyManager(@Nullable Environment environment); - - final class ReloadableX509KeyManager extends X509ExtendedKeyManager { - - private volatile X509ExtendedKeyManager keyManager; - - ReloadableX509KeyManager(X509ExtendedKeyManager keyManager) { - this.keyManager = keyManager; - } - - @Override - public String[] getClientAliases(String s, Principal[] principals) { - return keyManager.getClientAliases(s, principals); - } - - @Override - public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { - return keyManager.chooseClientAlias(strings, principals, socket); - } - - @Override - public String[] getServerAliases(String s, Principal[] principals) { - return keyManager.getServerAliases(s, principals); - } - - @Override - public String chooseServerAlias(String s, Principal[] principals, Socket socket) { - return keyManager.chooseServerAlias(s, principals, socket); - } - - @Override - public X509Certificate[] getCertificateChain(String s) { - return keyManager.getCertificateChain(s); - } - - @Override - public PrivateKey getPrivateKey(String s) { - return keyManager.getPrivateKey(s); - } - - @Override - public String chooseEngineClientAlias(String[] strings, Principal[] principals, SSLEngine engine) { - return keyManager.chooseEngineClientAlias(strings, principals, engine); - } - - @Override - public String chooseEngineServerAlias(String s, Principal[] principals, SSLEngine engine) { - return keyManager.chooseEngineServerAlias(s, principals, engine); - } - - synchronized void setKeyManager(X509ExtendedKeyManager x509ExtendedKeyManager) { - this.keyManager = x509ExtendedKeyManager; - } - - // pkg-private accessor for testing - X509ExtendedKeyManager getKeyManager() { - return keyManager; - } - } + abstract X509ExtendedKeyManager createKeyManager(@Nullable Environment environment); } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java index f0867e446cc..bf92e63e8ac 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java @@ -36,7 +36,7 @@ class PEMKeyConfig extends KeyConfig { } @Override - X509ExtendedKeyManager loadKeyManager(@Nullable Environment environment) { + X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { // password must be non-null for keystore... char[] password = keyPassword == null ? new char[0] : keyPassword.toCharArray(); try { diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java index a61eceb3def..71ae083862b 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java @@ -31,26 +31,26 @@ import static org.elasticsearch.xpack.security.support.OptionalSettings.createTi /** * Class that contains all configuration related to SSL use within x-pack */ -public abstract class SSLConfiguration { +abstract class SSLConfiguration { - public abstract KeyConfig keyConfig(); + abstract KeyConfig keyConfig(); - public abstract TrustConfig trustConfig(); + abstract TrustConfig trustConfig(); - public abstract String protocol(); + abstract String protocol(); - public abstract int sessionCacheSize(); + abstract int sessionCacheSize(); - public abstract TimeValue sessionCacheTimeout(); + abstract TimeValue sessionCacheTimeout(); - public abstract List ciphers(); + abstract List ciphers(); - public abstract List supportedProtocols(); + abstract List supportedProtocols(); /** * Provides the list of paths to files that back this configuration */ - public List filesToMonitor(@Nullable Environment environment) { + List filesToMonitor(@Nullable Environment environment) { if (keyConfig() == trustConfig()) { return keyConfig().filesToMonitor(environment); } @@ -59,30 +59,6 @@ public abstract class SSLConfiguration { return paths; } - /** - * Reloads the portion of this configuration that makes use of the modified file - */ - public void reload(Path file, @Nullable Environment environment) { - if (keyConfig() == trustConfig()) { - keyConfig().reload(environment); - return; - } - - for (Path path : keyConfig().filesToMonitor(environment)) { - if (file.equals(path)) { - keyConfig().reload(environment); - break; - } - } - - for (Path path : trustConfig().filesToMonitor(environment)) { - if (file.equals(path)) { - trustConfig().reload(environment); - break; - } - } - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -125,14 +101,14 @@ public abstract class SSLConfiguration { return result; } - public static class Global extends SSLConfiguration { + static class Global extends SSLConfiguration { - public static final List DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2"); - public static final List DEFAULT_CIPHERS = + static final List DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2"); + static final List DEFAULT_CIPHERS = Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"); - public static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24); - public static final int DEFAULT_SESSION_CACHE_SIZE = 1000; - public static final String DEFAULT_PROTOCOL = "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 = "TLSv1.2"; // common settings static final Setting> CIPHERS_SETTING = Setting.listSetting(globalKey(Custom.CIPHERS_SETTING), DEFAULT_CIPHERS, @@ -145,8 +121,6 @@ public abstract class SSLConfiguration { DEFAULT_SESSION_CACHE_SIZE, Property.NodeScope, Property.Filtered); static final Setting SESSION_CACHE_TIMEOUT_SETTING = Setting.timeSetting(globalKey(Custom.CACHE_TIMEOUT_SETTING), DEFAULT_SESSION_CACHE_TIMEOUT, Property.NodeScope, Property.Filtered); - static final Setting RELOAD_ENABLED_SETTING = - Setting.boolSetting(globalKey(Custom.RELOAD_ENABLED_SETTING), true, Property.NodeScope, Property.Filtered); // keystore settings static final Setting> KEYSTORE_PATH_SETTING = createString(globalKey(Custom.KEYSTORE_PATH_SETTING), @@ -185,27 +159,6 @@ public abstract class SSLConfiguration { static final Setting INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting(globalKey(Custom.INCLUDE_JDK_CERTS_SETTING), true, Property.NodeScope, Property.Filtered); - public static void addSettings(List> settings) { - settings.add(Global.CIPHERS_SETTING); - settings.add(Global.SUPPORTED_PROTOCOLS_SETTING); - settings.add(Global.KEYSTORE_PATH_SETTING); - settings.add(Global.KEYSTORE_PASSWORD_SETTING); - settings.add(Global.KEYSTORE_ALGORITHM_SETTING); - settings.add(Global.KEYSTORE_KEY_PASSWORD_SETTING); - settings.add(Global.KEY_PATH_SETTING); - settings.add(Global.KEY_PASSWORD_SETTING); - settings.add(Global.CERT_SETTING); - settings.add(Global.TRUSTSTORE_PATH_SETTING); - settings.add(Global.TRUSTSTORE_PASSWORD_SETTING); - settings.add(Global.TRUSTSTORE_ALGORITHM_SETTING); - settings.add(Global.PROTOCOL_SETTING); - settings.add(Global.SESSION_CACHE_SIZE_SETTING); - settings.add(Global.SESSION_CACHE_TIMEOUT_SETTING); - settings.add(Global.CA_PATHS_SETTING); - settings.add(Global.INCLUDE_JDK_CERTS_SETTING); - settings.add(Global.RELOAD_ENABLED_SETTING); - } - private final KeyConfig keyConfig; private final TrustConfig trustConfig; private final String sslProtocol; @@ -219,7 +172,7 @@ public abstract class SSLConfiguration { * * @param settings the global settings to build the SSL configuration from */ - public Global(Settings settings) { + Global(Settings settings) { this.keyConfig = createGlobalKeyConfig(settings); this.trustConfig = createGlobalTrustConfig(settings, keyConfig); this.sslProtocol = PROTOCOL_SETTING.get(settings); @@ -230,44 +183,44 @@ public abstract class SSLConfiguration { } @Override - public KeyConfig keyConfig() { + KeyConfig keyConfig() { return keyConfig; } @Override - public TrustConfig trustConfig() { + TrustConfig trustConfig() { return trustConfig; } @Override - public String protocol() { + String protocol() { return sslProtocol; } @Override - public int sessionCacheSize() { + int sessionCacheSize() { return sessionCacheSize; } @Override - public TimeValue sessionCacheTimeout() { + TimeValue sessionCacheTimeout() { return sessionCacheTimeout; } @Override - public List ciphers() { + List ciphers() { return ciphers; } @Override - public List supportedProtocols() { + List supportedProtocols() { return supportedProtocols; } @Override public String toString() { return "SSLConfiguration{" + - ", keyConfig=[" + keyConfig + + "keyConfig=[" + keyConfig + "], trustConfig=" + trustConfig + "], sslProtocol=['" + sslProtocol + '\'' + "], sessionCacheSize=[" + sessionCacheSize + @@ -291,7 +244,6 @@ public abstract class SSLConfiguration { } boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings); - boolean reloadEnabled = RELOAD_ENABLED_SETTING.get(settings); if (keyPath != null) { String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null); List certPaths = getListOrNull(CERT_SETTING, settings); @@ -330,7 +282,7 @@ public abstract class SSLConfiguration { } } - public static class Custom extends SSLConfiguration { + static class Custom extends SSLConfiguration { static final Setting> PROTOCOL_SETTING = createString("protocol"); static final Setting> CACHE_SIZE_SETTING = createInt("session.cache_size"); @@ -360,7 +312,6 @@ public abstract class SSLConfiguration { static final Setting> CA_PATHS_SETTING = Setting.listSetting("ca", Collections.emptyList(), s -> s); static final Setting INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting("trust_cacerts", true); - static final Setting RELOAD_ENABLED_SETTING = Setting.boolSetting("reload.enabled", true); private final KeyConfig keyConfig; private final TrustConfig trustConfig; @@ -376,7 +327,7 @@ public abstract class SSLConfiguration { * @param settings the profile settings to get the SSL configuration for * @param defaultConfig the default SSL configuration */ - public Custom(Settings settings, SSLConfiguration defaultConfig) { + Custom(Settings settings, SSLConfiguration defaultConfig) { Objects.requireNonNull(settings); this.keyConfig = createKeyConfig(settings, defaultConfig); this.trustConfig = createTrustConfig(settings, keyConfig, defaultConfig); @@ -388,44 +339,44 @@ public abstract class SSLConfiguration { } @Override - public KeyConfig keyConfig() { + KeyConfig keyConfig() { return keyConfig; } @Override - public TrustConfig trustConfig() { + TrustConfig trustConfig() { return trustConfig; } @Override - public String protocol() { + String protocol() { return sslProtocol; } @Override - public int sessionCacheSize() { + int sessionCacheSize() { return sessionCacheSize; } @Override - public TimeValue sessionCacheTimeout() { + TimeValue sessionCacheTimeout() { return sessionCacheTimeout; } @Override - public List ciphers() { + List ciphers() { return ciphers; } @Override - public List supportedProtocols() { + List supportedProtocols() { return supportedProtocols; } @Override public String toString() { return "SSLConfiguration{" + - ", keyConfig=[" + keyConfig + + "keyConfig=[" + keyConfig + "], trustConfig=" + trustConfig + "], sslProtocol=['" + sslProtocol + '\'' + "], sessionCacheSize=[" + sessionCacheSize + @@ -445,7 +396,6 @@ public abstract class SSLConfiguration { } boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings); - boolean reloadEnabled = RELOAD_ENABLED_SETTING.get(settings); if (keyPath != null) { String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null); List certPaths = getListOrNull(CERT_SETTING, settings); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java index 49c6da03bfb..5c2179b4096 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java @@ -12,14 +12,12 @@ import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService.Frequency; +import org.elasticsearch.xpack.security.ssl.SSLService.SSLContextHolder; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSessionContext; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -30,28 +28,19 @@ import java.util.concurrent.CopyOnWriteArraySet; * Ensures that the files backing an {@link SSLConfiguration} are monitored for changes and the underlying key/trust material is reloaded * and the {@link SSLContext} has existing sessions invalidated to force the use of the new key/trust material */ -public class SSLConfigurationReloader extends AbstractComponent implements AbstractSSLService.Listener { +public class SSLConfigurationReloader extends AbstractComponent { private final ConcurrentHashMap pathToChangeListenerMap = new ConcurrentHashMap<>(); private final Environment environment; private final ResourceWatcherService resourceWatcherService; - private final ServerSSLService serverSSLService; - private final ClientSSLService clientSSLService; + private final SSLService sslService; - public SSLConfigurationReloader(Settings settings, Environment env, ServerSSLService serverSSLService, - ClientSSLService clientSSLService, ResourceWatcherService resourceWatcher) { + public SSLConfigurationReloader(Settings settings, Environment env, SSLService sslService, ResourceWatcherService resourceWatcher) { super(settings); this.environment = env; this.resourceWatcherService = resourceWatcher; - this.serverSSLService = serverSSLService; - this.clientSSLService = clientSSLService; - serverSSLService.setListener(this); - clientSSLService.setListener(this); - } - - @Override - public void onSSLContextLoaded(SSLConfiguration sslConfiguration) { - startWatching(Collections.singleton(sslConfiguration)); + this.sslService = sslService; + startWatching(sslService.getLoadedSSLConfigurations()); } /** @@ -84,24 +73,11 @@ public class SSLConfigurationReloader extends AbstractComponent implements Abstr } /** - * Invalidates all of the sessions in the provided {@link SSLContext} + * Reloads the ssl context associated with this configuration. It is visible so that tests can override as needed */ - private static void invalidateAllSessions(SSLContext context) { - if (context != null) { - invalidateSessions(context.getClientSessionContext()); - invalidateSessions(context.getServerSessionContext()); - } - } - - /** - * Invalidates the sessions in the provided {@link SSLSessionContext} - */ - private static void invalidateSessions(SSLSessionContext sslSessionContext) { - Enumeration sessionIds = sslSessionContext.getIds(); - while (sessionIds.hasMoreElements()) { - byte[] sessionId = sessionIds.nextElement(); - sslSessionContext.getSession(sessionId).invalidate(); - } + void reloadSSLContext(SSLConfiguration configuration) { + logger.debug("reloading ssl configuration [{}]", configuration); + sslService.sslContextHolder(configuration).reload(); } /** @@ -140,9 +116,7 @@ public class SSLConfigurationReloader extends AbstractComponent implements Abstr public void onFileChanged(Path file) { for (SSLConfiguration sslConfiguration : sslConfigurations) { if (sslConfiguration.filesToMonitor(environment).contains(file)) { - sslConfiguration.reload(file, environment); - invalidateAllSessions(serverSSLService.getSSLContext(sslConfiguration)); - invalidateAllSessions(clientSSLService.getSSLContext(sslConfiguration)); + reloadSSLContext(sslConfiguration); } } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java new file mode 100644 index 00000000000..12eed7ff049 --- /dev/null +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java @@ -0,0 +1,653 @@ +/* + * 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.xpack.security.ssl; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.settings.Setting; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; +import org.elasticsearch.transport.TransportSettings; +import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Custom; +import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; +import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport; +import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static org.elasticsearch.xpack.security.Security.setting; +import static org.elasticsearch.xpack.security.Security.settingPrefix; +import static org.elasticsearch.xpack.security.authc.Realms.REALMS_GROUPS_SETTINGS; +import static org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport.SSL_SETTING; + +/** + * Provides access to {@link SSLEngine} and {@link SSLSocketFactory} objects based on a provided configuration. All + * configurations loaded by this service must be configured on construction. + */ +public class SSLService extends AbstractComponent { + + private final Map sslContexts; + private final SSLConfiguration globalSSLConfiguration; + private final Environment env; + + public SSLService(Settings settings, Environment environment) { + super(settings); + this.env = environment; + this.globalSSLConfiguration = new Global(settings); + this.sslContexts = loadSSLConfigurations(); + } + + /** + * Create a new {@link SSLSocketFactory} based on the provided settings. The settings are used to identify the ssl configuration that + * should be used to create the socket factory. The socket factory will also properly configure the ciphers and protocols on each + * socket that is created + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return + * a factory created from the default configuration + * @return {@link SSLSocketFactory} + */ + public SSLSocketFactory sslSocketFactory(Settings settings) { + SSLConfiguration sslConfiguration = sslConfiguration(settings); + SSLSocketFactory socketFactory = sslContext(sslConfiguration).getSocketFactory(); + return new SecuritySSLSocketFactory(socketFactory, sslConfiguration.supportedProtocols().toArray(Strings.EMPTY_ARRAY), + supportedCiphers(socketFactory.getSupportedCipherSuites(), sslConfiguration.ciphers(), false)); + } + + /** + * Creates an {@link SSLEngine} based on the provided settings. The settings are used to identify the ssl configuration that should be + * used to create the engine. This SSLEngine cannot be used for hostname verification since the engine will not be created with the + * host and port. This method is useful to obtain an SSLEngine that will be used for server connections or client connections that + * will not use hostname verification. + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return + * a SSLEngine created from the default configuration + * @return {@link SSLEngine} + */ + public SSLEngine createSSLEngine(Settings settings) { + return createSSLEngine(settings, null, -1); + } + + /** + * Creates an {@link SSLEngine} based on the provided settings. The settings are used to identify the ssl configuration that should be + * used to create the engine. This SSLEngine can be used for a connection that requires hostname verification assuming the provided + * host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verificaton enabled + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return + * a SSLEngine created from the default configuration + * @param host the host of the remote endpoint. If using hostname verification, this should match what is in the remote endpoint's + * certificate + * @param port the port of the remote endpoint + * @return {@link SSLEngine} + */ + public SSLEngine createSSLEngine(Settings settings, String host, int port) { + SSLConfiguration configuration = sslConfiguration(settings); + SSLContext sslContext = sslContext(configuration); + SSLEngine sslEngine = sslContext.createSSLEngine(host, port); + String[] ciphers = supportedCiphers(sslEngine.getSupportedCipherSuites(), configuration.ciphers(), false); + try { + sslEngine.setEnabledCipherSuites(ciphers); + } catch (ElasticsearchException e) { + throw e; + } catch (Exception e) { + throw new IllegalArgumentException("failed loading cipher suites " + Arrays.toString(ciphers), e); + } + + String[] supportedProtocols = configuration.supportedProtocols().toArray(Strings.EMPTY_ARRAY); + try { + sslEngine.setEnabledProtocols(supportedProtocols); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("failed setting supported protocols " + Arrays.toString(supportedProtocols), e); + } + return sslEngine; + } + + /** + * Returns whether the provided settings results in a valid configuration that can be used for server connections + */ + public boolean isConfigurationValidForServerUsage(Settings settings) { + SSLConfiguration sslConfiguration = sslConfiguration(settings); + return sslConfiguration.keyConfig() != KeyConfig.NONE; + } + + /** + * Returns the {@link SSLContext} for the global configuration. Mainly used for testing + */ + SSLContext sslContext() { + return sslContextHolder(globalSSLConfiguration).sslContext(); + } + + /** + * Returns the {@link SSLContext} for the configuration + */ + SSLContext sslContext(SSLConfiguration configuration) { + return sslContextHolder(configuration).sslContext(); + } + + /** + * Returns the existing {@link SSLContextHolder} for the configuration + * @throws IllegalArgumentException if not found + */ + SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) { + SSLContextHolder holder = sslContexts.get(sslConfiguration); + if (holder == null) { + throw new IllegalArgumentException("did not find a SSLContext for [" + sslConfiguration.toString() + "]"); + } + return holder; + } + + /** + * Returns the existing {@link SSLConfiguration} for the given settings + * @param settings the settings for the ssl configuration + * @return the ssl configuration for the provided settings. If the settings are empty, the global configuration is returned + */ + SSLConfiguration sslConfiguration(Settings settings) { + if (settings.isEmpty()) { + return globalSSLConfiguration; + } + return new Custom(settings, globalSSLConfiguration); + } + + /** + * Accessor to the loaded ssl configuration objects at the current point in time. This is useful for testing + */ + Collection getLoadedSSLConfigurations() { + return Collections.unmodifiableSet(new HashSet<>(sslContexts.keySet())); + } + + /** + * Returns the intersection of the supported ciphers with the requested ciphers. This method will also optionally log if unsupported + * ciphers were requested. + * @throws IllegalArgumentException if no supported ciphers are in the requested ciphers + */ + String[] supportedCiphers(String[] supportedCiphers, List requestedCiphers, boolean log) { + List supportedCiphersList = new ArrayList<>(requestedCiphers.size()); + List unsupportedCiphers = new LinkedList<>(); + boolean found; + for (String requestedCipher : requestedCiphers) { + found = false; + for (String supportedCipher : supportedCiphers) { + if (supportedCipher.equals(requestedCipher)) { + found = true; + supportedCiphersList.add(requestedCipher); + break; + } + } + + if (!found) { + unsupportedCiphers.add(requestedCipher); + } + } + + if (supportedCiphersList.isEmpty()) { + throw new IllegalArgumentException("none of the ciphers " + Arrays.toString(requestedCiphers.toArray()) + + " are supported by this JVM"); + } + + if (log && !unsupportedCiphers.isEmpty()) { + logger.error("unsupported ciphers [{}] were requested but cannot be used in this JVM, however there are supported ciphers " + + "that will be used [{}]. If you are trying to use ciphers with a key length greater than 128 bits on an Oracle JVM, " + + "you will need to install the unlimited strength JCE policy files.", unsupportedCiphers, supportedCiphersList); + } + + return supportedCiphersList.toArray(new String[supportedCiphersList.size()]); + } + + /** + * Creates an {@link SSLContext} based on the provided configuration + * @param sslConfiguration the configuration to use for context creation + * @return the created SSLContext + */ + private SSLContextHolder createSslContext(SSLConfiguration sslConfiguration) { + if (logger.isDebugEnabled()) { + logger.debug("using ssl settings [{}]", sslConfiguration); + } + ReloadableTrustManager trustManager = + new ReloadableTrustManager(sslConfiguration.trustConfig().createTrustManager(env), sslConfiguration.trustConfig()); + ReloadableX509KeyManager keyManager = + new ReloadableX509KeyManager(sslConfiguration.keyConfig().createKeyManager(env), sslConfiguration.keyConfig()); + + // Initialize sslContext + try { + SSLContext sslContext = SSLContext.getInstance(sslConfiguration.protocol()); + sslContext.init(new X509ExtendedKeyManager[] { keyManager }, new X509ExtendedTrustManager[] { trustManager }, null); + sslContext.getServerSessionContext().setSessionCacheSize(sslConfiguration.sessionCacheSize()); + sslContext.getServerSessionContext().setSessionTimeout(Math.toIntExact(sslConfiguration.sessionCacheTimeout().seconds())); + + // check the supported ciphers and log them here to prevent spamming logs on every call + supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), sslConfiguration.ciphers(), true); + + return new SSLContextHolder(sslContext, trustManager, keyManager); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new ElasticsearchException("failed to initialize the SSLContext", e); + } + } + + /** + * Parses the settings to load all SSLConfiguration objects that will be used. + */ + private Map loadSSLConfigurations() { + Map sslConfigurations = new HashMap<>(); + validateSSLConfiguration(globalSSLConfiguration); + sslConfigurations.put(globalSSLConfiguration, createSslContext(globalSSLConfiguration)); + List sslSettings = new ArrayList<>(); + sslSettings.addAll(getTransportSSLSettings(settings)); + sslSettings.addAll(getRealmsSSLSettings(settings)); + sslSettings.addAll(getHttpSSLSettings(settings)); + for (Settings settings : sslSettings) { + SSLConfiguration sslConfiguration = new Custom(settings, globalSSLConfiguration); + validateSSLConfiguration(sslConfiguration); + if (sslConfigurations.containsKey(sslConfiguration) == false) { + sslConfigurations.put(sslConfiguration, createSslContext(sslConfiguration)); + } + } + return Collections.unmodifiableMap(sslConfigurations); + } + + private void validateSSLConfiguration(SSLConfiguration configuration) { + configuration.keyConfig().validate(); + configuration.trustConfig().validate(); + } + + /** + * This socket factory wraps an existing SSLSocketFactory and sets the protocols and ciphers on each SSLSocket after it is created. This + * is needed even though the SSLContext is configured properly as the configuration does not flow down to the sockets created by the + * SSLSocketFactory obtained from the SSLContext. + */ + private static class SecuritySSLSocketFactory extends SSLSocketFactory { + + private final SSLSocketFactory delegate; + private final String[] supportedProtocols; + private final String[] ciphers; + + SecuritySSLSocketFactory(SSLSocketFactory delegate, String[] supportedProtocols, String[] ciphers) { + this.delegate = delegate; + this.supportedProtocols = supportedProtocols; + this.ciphers = ciphers; + } + + @Override + public String[] getDefaultCipherSuites() { + return ciphers; + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(); + configureSSLSocket(sslSocket); + return sslSocket; + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(socket, host, port, autoClose); + configureSSLSocket(sslSocket); + return sslSocket; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port); + configureSSLSocket(sslSocket); + return sslSocket; + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port, localHost, localPort); + configureSSLSocket(sslSocket); + return sslSocket; + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(host, port); + configureSSLSocket(sslSocket); + return sslSocket; + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + SSLSocket sslSocket = (SSLSocket) delegate.createSocket(address, port, localAddress, localPort); + configureSSLSocket(sslSocket); + return sslSocket; + } + + private void configureSSLSocket(SSLSocket socket) { + socket.setEnabledProtocols(supportedProtocols); + socket.setEnabledCipherSuites(ciphers); + } + } + + /** + * Wraps a trust manager to delegate to. If the trust material needs to be reloaded, then the delegate will be switched after + * reloading + */ + final class ReloadableTrustManager extends X509ExtendedTrustManager { + + private volatile X509ExtendedTrustManager trustManager; + private final TrustConfig trustConfig; + + ReloadableTrustManager(X509ExtendedTrustManager trustManager, TrustConfig trustConfig) { + this.trustManager = trustManager == null ? new EmptyX509TrustManager() : trustManager; + this.trustConfig = trustConfig; + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { + trustManager.checkClientTrusted(x509Certificates, s, socket); + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { + trustManager.checkServerTrusted(x509Certificates, s, socket); + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { + trustManager.checkClientTrusted(x509Certificates, s, sslEngine); + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { + trustManager.checkServerTrusted(x509Certificates, s, sslEngine); + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + trustManager.checkClientTrusted(x509Certificates, s); + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + trustManager.checkServerTrusted(x509Certificates, s); + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return trustManager.getAcceptedIssuers(); + } + + void reload() { + X509ExtendedTrustManager loadedTrustManager = trustConfig.createTrustManager(env); + if (loadedTrustManager == null) { + this.trustManager = new EmptyX509TrustManager(); + } else { + this.trustManager = loadedTrustManager; + } + } + + X509ExtendedTrustManager getTrustManager() { + return trustManager; + } + } + + /** + * Wraps a key manager and delegates all calls to it. When the key material needs to be reloaded, then the delegate is swapped after + * a new one has been loaded + */ + final class ReloadableX509KeyManager extends X509ExtendedKeyManager { + + private volatile X509ExtendedKeyManager keyManager; + private final KeyConfig keyConfig; + + ReloadableX509KeyManager(X509ExtendedKeyManager keyManager, KeyConfig keyConfig) { + this.keyManager = keyManager == null ? new EmptyKeyManager() : keyManager; + this.keyConfig = keyConfig; + } + + @Override + public String[] getClientAliases(String s, Principal[] principals) { + return keyManager.getClientAliases(s, principals); + } + + @Override + public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { + return keyManager.chooseClientAlias(strings, principals, socket); + } + + @Override + public String[] getServerAliases(String s, Principal[] principals) { + return keyManager.getServerAliases(s, principals); + } + + @Override + public String chooseServerAlias(String s, Principal[] principals, Socket socket) { + return keyManager.chooseServerAlias(s, principals, socket); + } + + @Override + public X509Certificate[] getCertificateChain(String s) { + return keyManager.getCertificateChain(s); + } + + @Override + public PrivateKey getPrivateKey(String s) { + return keyManager.getPrivateKey(s); + } + + @Override + public String chooseEngineClientAlias(String[] strings, Principal[] principals, SSLEngine engine) { + return keyManager.chooseEngineClientAlias(strings, principals, engine); + } + + @Override + public String chooseEngineServerAlias(String s, Principal[] principals, SSLEngine engine) { + return keyManager.chooseEngineServerAlias(s, principals, engine); + } + + void reload() { + X509ExtendedKeyManager loadedKeyManager = keyConfig.createKeyManager(env); + if (loadedKeyManager == null) { + this.keyManager = new EmptyKeyManager(); + } else { + this.keyManager = loadedKeyManager; + } + } + + // pkg-private accessor for testing + X509ExtendedKeyManager getKeyManager() { + return keyManager; + } + } + + /** + * A struct for holding the SSLContext and the backing key manager and trust manager + */ + static final class SSLContextHolder { + + private final SSLContext context; + private final ReloadableTrustManager trustManager; + private final ReloadableX509KeyManager keyManager; + + SSLContextHolder(SSLContext context, ReloadableTrustManager trustManager, ReloadableX509KeyManager keyManager) { + this.context = context; + this.trustManager = trustManager; + this.keyManager = keyManager; + } + + SSLContext sslContext() { + return context; + } + + ReloadableX509KeyManager keyManager() { + return keyManager; + } + + ReloadableTrustManager trustManager() { + return trustManager; + } + + synchronized void reload() { + trustManager.reload(); + keyManager.reload(); + invalidateSessions(context.getClientSessionContext()); + invalidateSessions(context.getServerSessionContext()); + } + + /** + * Invalidates the sessions in the provided {@link SSLSessionContext} + */ + private static void invalidateSessions(SSLSessionContext sslSessionContext) { + Enumeration sessionIds = sslSessionContext.getIds(); + while (sessionIds.hasMoreElements()) { + byte[] sessionId = sessionIds.nextElement(); + sslSessionContext.getSession(sessionId).invalidate(); + } + } + } + + /** + * This is an empty key manager that is used in case a loaded key manager is null + */ + private static final class EmptyKeyManager extends X509ExtendedKeyManager { + + @Override + public String[] getClientAliases(String s, Principal[] principals) { + return new String[0]; + } + + @Override + public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { + return null; + } + + @Override + public String[] getServerAliases(String s, Principal[] principals) { + return new String[0]; + } + + @Override + public String chooseServerAlias(String s, Principal[] principals, Socket socket) { + return null; + } + + @Override + public X509Certificate[] getCertificateChain(String s) { + return new X509Certificate[0]; + } + + @Override + public PrivateKey getPrivateKey(String s) { + return null; + } + } + + /** + * This is an empty trust manager that is used in case a loaded trust manager is null + */ + private static final class EmptyX509TrustManager extends X509ExtendedTrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { + } + + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + + public static void addSettings(List> settings) { + settings.add(Global.CIPHERS_SETTING); + settings.add(Global.SUPPORTED_PROTOCOLS_SETTING); + settings.add(Global.KEYSTORE_PATH_SETTING); + settings.add(Global.KEYSTORE_PASSWORD_SETTING); + settings.add(Global.KEYSTORE_ALGORITHM_SETTING); + settings.add(Global.KEYSTORE_KEY_PASSWORD_SETTING); + settings.add(Global.KEY_PATH_SETTING); + settings.add(Global.KEY_PASSWORD_SETTING); + settings.add(Global.CERT_SETTING); + settings.add(Global.TRUSTSTORE_PATH_SETTING); + settings.add(Global.TRUSTSTORE_PASSWORD_SETTING); + settings.add(Global.TRUSTSTORE_ALGORITHM_SETTING); + settings.add(Global.PROTOCOL_SETTING); + settings.add(Global.SESSION_CACHE_SIZE_SETTING); + settings.add(Global.SESSION_CACHE_TIMEOUT_SETTING); + settings.add(Global.CA_PATHS_SETTING); + settings.add(Global.INCLUDE_JDK_CERTS_SETTING); + } + + private static List getRealmsSSLSettings(Settings settings) { + List sslSettings = new ArrayList<>(); + Settings realmsSettings = REALMS_GROUPS_SETTINGS.get(settings); + for (String name : realmsSettings.names()) { + Settings realmSSLSettings = realmsSettings.getAsSettings(name).getByPrefix("ssl."); + if (realmSSLSettings.isEmpty() == false) { + sslSettings.add(realmSSLSettings); + } + } + return sslSettings; + } + + private static List getTransportSSLSettings(Settings settings) { + List sslSettings = new ArrayList<>(); + Map profiles = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true); + for (Entry entry : profiles.entrySet()) { + Settings profileSettings = entry.getValue(); + final boolean profileSsl = SecurityNetty4Transport.profileSSL(profileSettings, SSL_SETTING.get(settings)); + if (profileSsl && profileSettings.isEmpty() == false) { + sslSettings.add(profileSettings.getByPrefix(settingPrefix())); + } + } + return sslSettings; + } + + private static List getHttpSSLSettings(Settings settings) { + if (SecurityNetty4HttpServerTransport.SSL_SETTING.get(settings)) { + return Collections.singletonList(settings.getByPrefix(setting("http.ssl."))); + } + return Collections.emptyList(); + } +} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ServerSSLService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ServerSSLService.java deleted file mode 100644 index f8c0e78e2ba..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/ServerSSLService.java +++ /dev/null @@ -1,26 +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.xpack.security.ssl; - -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; - -public class ServerSSLService extends AbstractSSLService { - - public ServerSSLService(Settings settings, Environment environment, Global globalSSLConfiguration) { - super(settings, environment, globalSSLConfiguration); - } - - @Override - protected void validateSSLConfiguration(SSLConfiguration sslConfiguration) { - if (sslConfiguration.keyConfig() == KeyConfig.NONE) { - throw new IllegalArgumentException("a key must be configured to act as a server"); - } - sslConfiguration.keyConfig().validate(); - sslConfiguration.trustConfig().validate(); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java index 24bf267b0d8..b8e5c074c84 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java @@ -37,7 +37,7 @@ class StoreKeyConfig extends KeyConfig { } @Override - X509ExtendedKeyManager loadKeyManager(@Nullable Environment environment) { + X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) { // TODO remove reliance on JKS since we can PKCS12 stores... KeyStore ks = KeyStore.getInstance("jks"); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java index db1a8ef40ea..1c7cb2571cc 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java @@ -10,10 +10,7 @@ import org.elasticsearch.common.Nullable; import org.elasticsearch.env.Environment; import javax.net.ssl.X509ExtendedTrustManager; -import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Path; -import java.security.KeyStore; import java.util.Collections; import java.util.List; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java index 1a3268b0027..b6196073ed5 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java @@ -24,34 +24,18 @@ abstract class TrustConfig { protected final boolean includeSystem; - X509ExtendedTrustManager[] trustManagers = null; - TrustConfig(boolean includeSystem) { this.includeSystem = includeSystem; } - final synchronized X509ExtendedTrustManager[] trustManagers(@Nullable Environment environment) { - if (trustManagers == null) { - X509ExtendedTrustManager loadedTrustManager = loadAndMergeIfNecessary(environment); - setTrustManagers(loadedTrustManager); - } - return trustManagers; - } - - synchronized void reload(@Nullable Environment environment) { - X509ExtendedTrustManager loadedTrustManager = loadAndMergeIfNecessary(environment); - setTrustManagers(loadedTrustManager); - } - - final synchronized void setTrustManagers(X509ExtendedTrustManager loadedTrustManager) { - if (loadedTrustManager == null) { - this.trustManagers = new X509ExtendedTrustManager[0]; - } else if (this.trustManagers == null || this.trustManagers.length == 0) { - this.trustManagers = new X509ExtendedTrustManager[] { new ReloadableTrustManager(loadedTrustManager) }; - } else { - assert this.trustManagers[0] instanceof ReloadableTrustManager; - ((ReloadableTrustManager)this.trustManagers[0]).setTrustManager(loadedTrustManager); + final X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager trustManager = nonSystemTrustManager(environment); + if (includeSystem) { + trustManager = mergeWithSystem(trustManager); + } else if (trustManager == null) { + return null; } + return trustManager; } abstract X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment); @@ -62,16 +46,6 @@ abstract class TrustConfig { public abstract String toString(); - final X509ExtendedTrustManager loadAndMergeIfNecessary(@Nullable Environment environment) { - X509ExtendedTrustManager trustManager = nonSystemTrustManager(environment); - if (includeSystem) { - trustManager = mergeWithSystem(trustManager); - } else if (trustManager == null) { - return null; - } - return trustManager; - } - private X509ExtendedTrustManager mergeWithSystem(X509ExtendedTrustManager nonSystemTrustManager) { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -179,56 +153,4 @@ abstract class TrustConfig { return acceptedIssuers; } } - - final class ReloadableTrustManager extends X509ExtendedTrustManager { - - private volatile X509ExtendedTrustManager trustManager; - - ReloadableTrustManager(X509ExtendedTrustManager trustManager) { - this.trustManager = trustManager; - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { - trustManager.checkClientTrusted(x509Certificates, s, socket); - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { - trustManager.checkServerTrusted(x509Certificates, s, socket); - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { - trustManager.checkClientTrusted(x509Certificates, s, sslEngine); - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { - trustManager.checkServerTrusted(x509Certificates, s, sslEngine); - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - trustManager.checkClientTrusted(x509Certificates, s); - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - trustManager.checkServerTrusted(x509Certificates, s); - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return trustManager.getAcceptedIssuers(); - } - - synchronized void setTrustManager(X509ExtendedTrustManager trustManager) { - this.trustManager = trustManager; - } - - X509ExtendedTrustManager getTrustManager() { - return trustManager; - } - } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java index 9b47f0265c7..a08df4a2106 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java @@ -58,7 +58,7 @@ public enum SSLClientAuth { case "true": return REQUIRED; default: - throw new IllegalArgumentException("could not resolve ssl client auth auth. unknown ssl client auth value [" + value + "]"); + throw new IllegalArgumentException("could not resolve ssl client auth. unknown ssl client auth value [" + value + "]"); } } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransport.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransport.java index 2ce3cbf38b3..0e2843afb08 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransport.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransport.java @@ -12,7 +12,7 @@ import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.http.netty3.Netty3HttpServerTransport; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.threadpool.ThreadPool; @@ -47,13 +47,13 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope); private final IPFilter ipFilter; - private final ServerSSLService sslService; + private final SSLService sslService; private final boolean ssl; private final Settings sslSettings; @Inject public SecurityNetty3HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter, - ServerSSLService sslService, ThreadPool threadPool) { + SSLService sslService, ThreadPool threadPool) { super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; this.ssl = SSL_SETTING.get(settings); @@ -109,6 +109,9 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport public HttpSslChannelPipelineFactory(Netty3HttpServerTransport transport) { super(transport, detailedErrorsEnabled, threadPool.getThreadContext()); clientAuth = CLIENT_AUTH_SETTING.get(settings); + if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server"); + } } @Override diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3Transport.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3Transport.java index 3803695eaa7..0433ac38eda 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3Transport.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3Transport.java @@ -15,8 +15,7 @@ import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.threadpool.ThreadPool; @@ -91,21 +90,18 @@ public class SecurityNetty3Transport extends Netty3Transport { SSLClientAuth::parse, new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - private final ServerSSLService serverSslService; - private final ClientSSLService clientSSLService; + private final SSLService sslService; @Nullable private final IPFilter authenticator; private final boolean ssl; @Inject public SecurityNetty3Transport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, - @Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, - ClientSSLService clientSSLService, NamedWriteableRegistry namedWriteableRegistry, + @Nullable IPFilter authenticator, SSLService sslService, NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService) { super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService); this.authenticator = authenticator; this.ssl = SSL_SETTING.get(settings); - this.serverSslService = serverSSLService; - this.clientSSLService = clientSSLService; + this.sslService = sslService; } @Override @@ -161,28 +157,27 @@ public class SecurityNetty3Transport extends Netty3Transport { private class SslServerChannelPipelineFactory extends ServerChannelPipelineFactory { - private final Settings profileSettings; + private final boolean sslEnabled; + private final Settings securityProfileSettings; + private final SSLClientAuth sslClientAuth; public SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) { super(nettyTransport, name, settings); - this.profileSettings = profileSettings; + this.sslEnabled = profileSsl(profileSettings, settings); + this.securityProfileSettings = profileSettings.getByPrefix(settingPrefix()); + this.sslClientAuth = PROFILE_CLIENT_AUTH_SETTING.get(profileSettings, settings); + if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server"); + } } @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = super.getPipeline(); - final boolean profileSsl = profileSsl(profileSettings, settings); - final SSLClientAuth clientAuth = PROFILE_CLIENT_AUTH_SETTING.get(profileSettings, settings); - if (profileSsl) { - SSLEngine serverEngine; - Settings securityProfileSettings = profileSettings.getByPrefix(settingPrefix()); - if (securityProfileSettings.names().isEmpty() == false) { - serverEngine = serverSslService.createSSLEngine(securityProfileSettings); - } else { - serverEngine = serverSslService.createSSLEngine(); - } + if (sslEnabled) { + SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings); serverEngine.setUseClientMode(false); - clientAuth.configure(serverEngine); + sslClientAuth.configure(serverEngine); pipeline.addFirst("ssl", new SslHandler(serverEngine)); } @@ -219,7 +214,7 @@ public class SecurityNetty3Transport extends Netty3Transport { SSLEngine sslEngine; if (HOSTNAME_VERIFICATION_SETTING.get(settings)) { InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue(); - sslEngine = clientSSLService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress), + sslEngine = sslService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress), inetSocketAddress.getPort()); // By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification @@ -229,7 +224,7 @@ public class SecurityNetty3Transport extends Netty3Transport { parameters.setEndpointIdentificationAlgorithm("HTTPS"); sslEngine.setSSLParameters(parameters); } else { - sslEngine = clientSSLService.createSSLEngine(); + sslEngine = sslService.createSSLEngine(Settings.EMPTY); } sslEngine.setUseClientMode(true); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransport.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransport.java index 941d983db6a..4c4276a27d7 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransport.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransport.java @@ -8,7 +8,6 @@ package org.elasticsearch.xpack.security.transport.netty4; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.socket.SocketChannel; import io.netty.handler.ssl.SslHandler; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.network.NetworkService; @@ -18,7 +17,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.http.netty4.Netty4HttpServerTransport; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; @@ -44,13 +43,13 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope); private final IPFilter ipFilter; - private final ServerSSLService sslService; + private final SSLService sslService; private final boolean ssl; private final Settings sslSettings; @Inject public SecurityNetty4HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter, - ServerSSLService sslService, ThreadPool threadPool) { + SSLService sslService, ThreadPool threadPool) { super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; this.ssl = SSL_SETTING.get(settings); @@ -105,6 +104,9 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport HttpSslChannelHandler(Netty4HttpServerTransport transport) { super(transport, detailedErrorsEnabled, threadPool.getThreadContext()); clientAuth = CLIENT_AUTH_SETTING.get(settings); + if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server"); + } } @Override @@ -132,5 +134,4 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport settingsBuilder.put(SETTING_HTTP_COMPRESSION.getKey(), false); } } - } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java index 7ab0c9d7afa..a58bed38d5a 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java @@ -26,8 +26,7 @@ import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.netty4.Netty4Transport; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; @@ -98,8 +97,7 @@ public class SecurityNetty4Transport extends Netty4Transport { SSLClientAuth::parse, new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - private final ServerSSLService serverSslService; - private final ClientSSLService clientSSLService; + private final SSLService sslService; @Nullable private final IPFilter authenticator; private final SSLClientAuth clientAuth; private final boolean ssl; @@ -107,14 +105,12 @@ public class SecurityNetty4Transport extends Netty4Transport { @Inject public SecurityNetty4Transport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService, - @Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, - ClientSSLService clientSSLService) { + @Nullable IPFilter authenticator, SSLService sslService) { super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService); this.authenticator = authenticator; this.ssl = SSL_SETTING.get(settings); this.clientAuth = CLIENT_AUTH_SETTING.get(settings); - this.serverSslService = serverSSLService; - this.clientSSLService = clientSSLService; + this.sslService = sslService; } @Override @@ -160,18 +156,22 @@ public class SecurityNetty4Transport extends Netty4Transport { class SecurityServerChannelInitializer extends ServerChannelInitializer { private final boolean sslEnabled; + private final Settings securityProfileSettings; protected SecurityServerChannelInitializer(String name, Settings settings) { super(name, settings); this.sslEnabled = profileSSL(settings, ssl); + this.securityProfileSettings = settings.getByPrefix(settingPrefix()); + if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server"); + } } @Override protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); if (sslEnabled) { - Settings securityProfileSettings = settings.getByPrefix(settingPrefix()); - SSLEngine serverEngine = serverSslService.createSSLEngine(securityProfileSettings); + SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings); serverEngine.setUseClientMode(false); final SSLClientAuth profileClientAuth = profileClientAuth(settings, clientAuth); profileClientAuth.configure(serverEngine); @@ -201,7 +201,7 @@ public class SecurityNetty4Transport extends Netty4Transport { final SSLEngine sslEngine; if (HOSTNAME_VERIFICATION_SETTING.get(settings)) { InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress; - sslEngine = clientSSLService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress), inetSocketAddress.getPort()); + sslEngine = sslService.createSSLEngine(Settings.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 @@ -210,7 +210,7 @@ public class SecurityNetty4Transport extends Netty4Transport { parameters.setEndpointIdentificationAlgorithm("HTTPS"); sslEngine.setSSLParameters(parameters); } else { - sslEngine = clientSSLService.createSSLEngine(); + sslEngine = sslService.createSSLEngine(Settings.EMPTY); } sslEngine.setUseClientMode(true); @@ -235,7 +235,7 @@ public class SecurityNetty4Transport extends Netty4Transport { } } - static boolean profileSSL(Settings profileSettings, boolean defaultSSL) { + public static boolean profileSSL(Settings profileSettings, boolean defaultSSL) { if (PROFILE_SSL_SETTING.exists(profileSettings)) { return PROFILE_SSL_SETTING.get(profileSettings); } else if (DEPRECATED_PROFILE_SSL_SETTING.exists(profileSettings)) { @@ -251,5 +251,4 @@ public class SecurityNetty4Transport extends Netty4Transport { } return clientAuth; } - } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java index b38dbc16371..830361379a5 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SettingsFilterTests.java @@ -11,7 +11,6 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.settings.SettingsModule; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration; import org.elasticsearch.xpack.XPackPlugin; import org.hamcrest.Matcher; @@ -56,7 +55,7 @@ public class SettingsFilterTests extends ESTestCase { configureFilteredSetting("xpack.security.ssl.keystore.path", "/path/to/keystore"); configureFilteredSetting("xpack.security.ssl.ciphers", "_ciphers"); - configureFilteredSetting("xpack.security.ssl.supported_protocols", randomFrom(SSLConfiguration.Global.DEFAULT_SUPPORTED_PROTOCOLS)); + configureFilteredSetting("xpack.security.ssl.supported_protocols", randomFrom("TLSv1", "TLSv1.1", "TLSv1.2")); configureFilteredSetting("xpack.security.ssl.keystore.password", randomAsciiOfLength(5)); configureFilteredSetting("xpack.security.ssl.keystore.algorithm", "_algorithm"); configureFilteredSetting("xpack.security.ssl.keystore.key_password", randomAsciiOfLength(5)); @@ -68,7 +67,7 @@ public class SettingsFilterTests extends ESTestCase { configureFilteredSetting("transport.profiles.client.xpack.security.keystore.path", "/path/to/keystore"); configureFilteredSetting("transport.profiles.client.xpack.security.ciphers", "_ciphers"); configureFilteredSetting("transport.profiles.client.xpack.security.supported_protocols", - randomFrom(SSLConfiguration.Global.DEFAULT_SUPPORTED_PROTOCOLS)); + randomFrom("TLSv1", "TLSv1.1", "TLSv1.2")); configureFilteredSetting("transport.profiles.client.xpack.security.keystore.password", randomAsciiOfLength(5)); configureFilteredSetting("transport.profiles.client.xpack.security.keystore.algorithm", "_algorithm"); configureFilteredSetting("transport.profiles.client.xpack.security.keystore.key_password", randomAsciiOfLength(5)); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/AbstractActiveDirectoryIntegTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/AbstractActiveDirectoryIntegTests.java index c17e6c5baa3..9c6489908b8 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/AbstractActiveDirectoryIntegTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/AbstractActiveDirectoryIntegTests.java @@ -8,10 +8,9 @@ package org.elasticsearch.xpack.security.authc.activedirectory; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.junit.Before; import java.nio.file.Path; @@ -23,7 +22,7 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase { public static final String PASSWORD = "NickFuryHeartsES"; public static final String AD_DOMAIN = "ad.test.elasticsearch.com"; - protected ClientSSLService clientSSLService; + protected SSLService sslService; protected Settings globalSettings; protected boolean useGlobalSSL; @@ -40,10 +39,14 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.security.ssl.keystore.path", keystore) .put("xpack.security.ssl.keystore.password", "changeit"); + } else { + // fake a realm so ssl will get loaded + builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); + builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit"); } globalSettings = builder.build(); Environment environment = new Environment(globalSettings); - clientSSLService = new ClientSSLService(globalSettings, environment, new Global(globalSettings)); + sslService = new SSLService(globalSettings, environment); } Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope, diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactoryTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactoryTests.java index 8f0a1120a72..574d9c5affa 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactoryTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectorySessionFactoryTests.java @@ -16,7 +16,6 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.test.junit.annotations.Network; -import java.io.IOException; import java.util.List; import static org.hamcrest.Matchers.anyOf; @@ -31,7 +30,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI @SuppressWarnings("unchecked") public void testAdAuth() throws Exception { RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "ironman"; try (LdapSession ldap = sessionFactory.session(userName, SecuredStringTests.build(PASSWORD))) { @@ -52,7 +51,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI public void testNetbiosAuth() throws Exception { final String adUrl = randomFrom("ldap://54.213.145.20:3268", "ldaps://54.213.145.20:3269", AD_LDAP_URL); RealmConfig config = new RealmConfig("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false), globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "ades\\ironman"; try (LdapSession ldap = sessionFactory.session(userName, SecuredStringTests.build(PASSWORD))) { @@ -79,7 +78,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI .put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); LDAPException expected = expectThrows(LDAPException.class, () -> sessionFactory.session("ironman", SecuredStringTests.build(PASSWORD)).groups()); @@ -88,7 +87,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI public void testAdAuthAvengers() throws Exception { RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String[] users = new String[]{"cap", "hawkeye", "hulk", "ironman", "thor", "blackwidow", }; for(String user: users) { @@ -103,7 +102,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "hulk"; try (LdapSession ldap = sessionFactory.session(userName, SecuredStringTests.build(PASSWORD))) { @@ -125,7 +124,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Bruce Banner, CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.BASE, false); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "hulk"; try (LdapSession ldap = sessionFactory.session(userName, SecuredStringTests.build(PASSWORD))) { @@ -151,7 +150,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI .put(ActiveDirectorySessionFactory.AD_GROUP_SEARCH_SCOPE_SETTING, LdapSearchScope.BASE) .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "hulk"; try (LdapSession ldap = sessionFactory.session(userName, SecuredStringTests.build(PASSWORD))) { @@ -166,7 +165,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); //Login with the UserPrincipalName String userDN = "CN=Erik Selvig,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; @@ -184,7 +183,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", LdapSearchScope.ONE_LEVEL, false); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); //login with sAMAccountName String userDN = "CN=Erik Selvig,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; @@ -208,7 +207,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI "(&(objectclass=user)(userPrincipalName={0}@ad.test.elasticsearch.com))") .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); //Login with the UserPrincipalName try (LdapSession ldap = sessionFactory.session("erik.selvig", SecuredStringTests.build(PASSWORD))) { @@ -234,7 +233,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI .build(); } RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Bruce Banner"; try (LdapSession ldap = sessionFactory.session(user, SecuredStringTests.build(PASSWORD))) { @@ -260,7 +259,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI .build(); } RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Bruce Banner"; try (LdapSession ldap = sessionFactory.session(user, SecuredStringTests.build(PASSWORD))) { @@ -276,7 +275,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI public void testAdAuthWithHostnameVerification() throws Exception { RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, true), globalSettings); - ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService); String userName = "ironman"; LDAPException expected = @@ -292,7 +291,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryI .put(LdapSessionFactory.HOSTNAME_VERIFICATION_SETTING, true) .build(); RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "Bruce Banner"; LDAPException expected = expectThrows(LDAPException.class, () -> sessionFactory.session(user, SecuredStringTests.build(PASSWORD))); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java index dde4ba5f99c..3791ff8906d 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/GroupsResolverTestCase.java @@ -11,9 +11,8 @@ import com.unboundid.ldap.sdk.LDAPURL; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.junit.After; import org.junit.Before; @@ -37,10 +36,14 @@ public abstract class GroupsResolverTestCase extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.security.ssl.keystore.path", keystore) .put("xpack.security.ssl.keystore.password", "changeit"); + } else { + // fake a realm so ssl will get loaded + builder.put("xpack.security.authc.realms.foo.ssl.keystore.path", keystore); + builder.put("xpack.security.authc.realms.foo.ssl.keystore.password", "changeit"); } Settings settings = builder.build(); Environment env = new Environment(settings); - ClientSSLService clientSSLService = new ClientSSLService(settings, env, new Global(settings)); + SSLService sslService = new SSLService(settings, env); LDAPURL ldapurl = new LDAPURL(ldapUrl()); LDAPConnectionOptions options = new LDAPConnectionOptions(); @@ -57,7 +60,7 @@ public abstract class GroupsResolverTestCase extends ESTestCase { .put("keystore.password", "changeit").build(); } - ldapConnection = new LDAPConnection(clientSSLService.sslSocketFactory(connectionSettings), options, ldapurl.getHost(), + ldapConnection = new LDAPConnection(sslService.sslSocketFactory(connectionSettings), options, ldapurl.getHost(), ldapurl.getPort(), bindDN(), bindPassword()); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java index 1ce62427315..3cf8ddd03e8 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java @@ -25,8 +25,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.support.NoOpLogger; import org.elasticsearch.test.junit.annotations.Network; import org.junit.Before; @@ -46,7 +45,7 @@ import static org.hamcrest.Matchers.nullValue; public class LdapUserSearchSessionFactoryTests extends LdapTestCase { - private ClientSSLService clientSSLService; + private SSLService sslService; private Settings globalSettings; @Before @@ -58,13 +57,12 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { * 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. */ - Settings settings = Settings.builder() + globalSettings = Settings.builder() + .put("path.home", createTempDir()) .put("xpack.security.ssl.keystore.path", keystore) .put("xpack.security.ssl.keystore.password", "changeit") .build(); - clientSSLService = new ClientSSLService(settings, env, new Global(settings)); - - globalSettings = Settings.builder().put("path.home", createTempDir()).build(); + sslService = new SSLService(globalSettings, env); } public void testSupportsUnauthenticatedSessions() throws Exception { @@ -359,7 +357,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("user_search.pool.enabled", randomBoolean()) .build(); RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, clientSSLService); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String user = "Bruce Banner"; try { @@ -401,7 +399,7 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { .put("bind_password", OpenLdapTests.PASSWORD) .put("user_search.pool.enabled", randomBoolean()) .build(), globalSettings); - LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, clientSSLService); + LdapUserSearchSessionFactory sessionFactory = new LdapUserSearchSessionFactory(config, sslService); String[] users = new String[] { "cap", "hawkeye", "hulk", "ironman", "thor" }; try { diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java index 57963d11341..dacf3231201 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/OpenLdapTests.java @@ -14,10 +14,9 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession; import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.junit.Before; import java.nio.file.Path; @@ -33,7 +32,7 @@ public class OpenLdapTests extends ESTestCase { public static final String PASSWORD = "NickFuryHeartsES"; private boolean useGlobalSSL; - private ClientSSLService clientSSLService; + private SSLService sslService; private Settings globalSettings; @Before @@ -49,10 +48,14 @@ public class OpenLdapTests extends ESTestCase { if (useGlobalSSL) { builder.put("xpack.security.ssl.keystore.path", keystore) .put("xpack.security.ssl.keystore.password", "changeit"); + } else { + // fake a realm so ssl will get loaded + builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); + builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit"); } globalSettings = builder.build(); Environment environment = new Environment(globalSettings); - clientSSLService = new ClientSSLService(globalSettings, environment, new Global(globalSettings)); + sslService = new SSLService(globalSettings, environment); } public void testConnect() throws Exception { @@ -61,7 +64,7 @@ public class OpenLdapTests extends ESTestCase { String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL), globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" }; for (String user : users) { @@ -78,7 +81,7 @@ public class OpenLdapTests extends ESTestCase { String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.BASE), globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" }; for (String user : users) { @@ -97,7 +100,7 @@ public class OpenLdapTests extends ESTestCase { .put("group_search.user_attribute", "uid") .build(); RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); try (LdapSession ldap = sessionFactory.session("selvig", SecuredStringTests.build(PASSWORD))){ assertThat(ldap.groups(), hasItem(containsString("Geniuses"))); @@ -115,7 +118,7 @@ public class OpenLdapTests extends ESTestCase { .put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond .build(); RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); LDAPException expected = expectThrows(LDAPException.class, () -> sessionFactory.session("thor", SecuredStringTests.build(PASSWORD)).groups()); @@ -132,7 +135,7 @@ public class OpenLdapTests extends ESTestCase { .build(); RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings); - LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService); String user = "blackwidow"; LDAPException expected = expectThrows(LDAPException.class, () -> sessionFactory.session(user, SecuredStringTests.build(PASSWORD))); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java index 3e9f855e689..e34b71a7239 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactoryLoadBalancingTests.java @@ -10,7 +10,7 @@ import com.unboundid.ldap.sdk.LDAPConnection; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import java.util.ArrayList; import java.util.Arrays; @@ -171,7 +171,7 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase { static class TestSessionFactory extends SessionFactory { - protected TestSessionFactory(RealmConfig config, ClientSSLService sslService) { + protected TestSessionFactory(RealmConfig config, SSLService sslService) { super(config, sslService); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java index 23b162b06d1..c502755166a 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java @@ -14,14 +14,10 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.xpack.security.ssl.KeyConfig.ReloadableX509KeyManager; import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.TrustConfig.ReloadableTrustManager; -import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; -import javax.net.ssl.SSLContext; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509ExtendedTrustManager; import java.io.IOException; @@ -44,7 +40,6 @@ import java.util.function.BiFunction; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.core.Is.is; @@ -301,40 +296,24 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final Global config = new Global(settings); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, config) { + final SSLService sslService = new SSLService(settings, env); + final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) { @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [keystore reload exception]"); - return super.getSSLContext(configuration); + void reloadSSLContext(SSLConfiguration configuration) { + fail("reload should not be called! [keystore reload exception]"); } }; - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, config) { - @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [keystore reload exception]"); - return super.getSSLContext(configuration); - } - }; - final SSLConfigurationReloader reloader = - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); - reloader.onSSLContextLoaded(config); // key manager checks - X509ExtendedKeyManager keyManager = ((ReloadableX509KeyManager)config.keyConfig().keyManagers(env)[0]).getKeyManager(); - String[] aliases = keyManager.getServerAliases("RSA", null); - assertNotNull(aliases); - assertThat(aliases.length, is(1)); - assertThat(aliases[0], is("testnode")); - PrivateKey privateKey = keyManager.getPrivateKey("testnode"); + final X509ExtendedKeyManager keyManager = sslService.sslContextHolder(config).keyManager().getKeyManager(); // truncate the keystore try (OutputStream out = Files.newOutputStream(keystorePath, StandardOpenOption.TRUNCATE_EXISTING)) { } // we intentionally don't wait here as we rely on concurrency to catch a failure - assertThat(keyManager.getServerAliases("RSA", null), equalTo(aliases)); - assertThat(keyManager.getPrivateKey("testnode"), is(equalTo(privateKey))); + assertThat(sslService.sslContextHolder(config).keyManager().getKeyManager(), sameInstance(keyManager)); } /** @@ -357,39 +336,23 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final Global config = new Global(settings); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, config) { + final SSLService sslService = new SSLService(settings, env); + final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) { @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [pem key reload exception]"); - return super.getSSLContext(configuration); + void reloadSSLContext(SSLConfiguration configuration) { + fail("reload should not be called! [pem key reload exception]"); } }; - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, config) { - @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [pem key reload exception]"); - return super.getSSLContext(configuration); - } - }; - final SSLConfigurationReloader reloader = - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); - reloader.onSSLContextLoaded(config); - X509ExtendedKeyManager keyManager = ((ReloadableX509KeyManager)config.keyConfig().keyManagers(env)[0]).getKeyManager(); - String[] aliases = keyManager.getServerAliases("RSA", null); - assertNotNull(aliases); - assertThat(aliases.length, is(1)); - assertThat(aliases[0], is("key")); - PrivateKey privateKey = keyManager.getPrivateKey("key"); + final X509ExtendedKeyManager keyManager = sslService.sslContextHolder(config).keyManager().getKeyManager(); // truncate the file try (OutputStream os = Files.newOutputStream(keyPath, StandardOpenOption.TRUNCATE_EXISTING)) { } // we intentionally don't wait here as we rely on concurrency to catch a failure - assertThat(keyManager.getServerAliases("RSA", null), equalTo(aliases)); - assertThat(keyManager.getPrivateKey("key"), is(equalTo(privateKey))); + assertThat(sslService.sslContextHolder(config).keyManager().getKeyManager(), sameInstance(keyManager)); } /** @@ -406,36 +369,23 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final Global config = new Global(settings); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, config) { + final SSLService sslService = new SSLService(settings, env); + final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) { @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [truststore reload exception]"); - return super.getSSLContext(configuration); + void reloadSSLContext(SSLConfiguration configuration) { + fail("reload should not be called! [truststore reload exception]"); } }; - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, config) { - @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [truststore reload exception]"); - return super.getSSLContext(configuration); - } - }; - final SSLConfigurationReloader reloader = - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); - reloader.onSSLContextLoaded(config); - X509ExtendedTrustManager trustManager = ((ReloadableTrustManager)config.trustConfig().trustManagers(env)[0]).getTrustManager(); - final Certificate[] certificates = trustManager.getAcceptedIssuers(); - assertContainsCertificateWithMatchingName(certificates, containsString("Test Node")); + final X509ExtendedTrustManager trustManager = sslService.sslContextHolder(config).trustManager().getTrustManager(); // truncate the truststore try (OutputStream os = Files.newOutputStream(trustStorePath, StandardOpenOption.TRUNCATE_EXISTING)) { } // we intentionally don't wait here as we rely on concurrency to catch a failure - assertThat(trustManager.getAcceptedIssuers(), equalTo(certificates)); - assertContainsCertificateWithMatchingName(trustManager.getAcceptedIssuers(), containsString("Test Node")); + assertThat(sslService.sslContextHolder(config).trustManager().getTrustManager(), sameInstance(trustManager)); } /** @@ -451,28 +401,16 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final Global config = new Global(settings); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, config) { + final SSLService sslService = new SSLService(settings, env); + final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) { @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [pem trust reload exception]"); - return super.getSSLContext(configuration); + void reloadSSLContext(SSLConfiguration configuration) { + fail("reload should not be called! [pem trust reload exception]"); } }; - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, config) { - @Override - SSLContext getSSLContext(SSLConfiguration configuration) { - fail("get should not be called! [pem trust reload exception]"); - return super.getSSLContext(configuration); - } - }; - final SSLConfigurationReloader reloader = - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); - reloader.onSSLContextLoaded(config); - X509ExtendedTrustManager trustManager = ((ReloadableTrustManager)config.trustConfig().trustManagers(env)[0]).getTrustManager(); - final Certificate[] certificates = trustManager.getAcceptedIssuers(); - assertContainsCertificateWithMatchingName(certificates, containsString("Test Client")); + final X509ExtendedTrustManager trustManager = sslService.sslContextHolder(config).trustManager().getTrustManager(); // write bad file Path updatedCert = tempDir.resolve("updated.crt"); @@ -482,8 +420,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase { atomicMoveIfPossible(updatedCert, clientCertPath); // we intentionally don't wait here as we rely on concurrency to catch a failure - assertThat(trustManager.getAcceptedIssuers(), equalTo(certificates)); - assertContainsCertificateWithMatchingName(trustManager.getAcceptedIssuers(), containsString("Test Client")); + assertThat(sslService.sslContextHolder(config).trustManager().getTrustManager(), sameInstance(trustManager)); } /** @@ -532,116 +469,62 @@ public class SSLConfigurationReloaderTests extends ESTestCase { BiFunction trustManagerPostChecks) throws Exception { - final AtomicInteger serverCounter = new AtomicInteger(0); - final AtomicInteger clientCounter = new AtomicInteger(0); - final Global config = new Global(settings); - final ServerSSLService serverSSLService = new ServerSSLService(settings, env, config) { + final AtomicInteger counter = new AtomicInteger(0); + final SSLService sslService = new SSLService(settings, env); + final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) { @Override - SSLContext getSSLContext(SSLConfiguration sslConfiguration) { - serverCounter.incrementAndGet(); - return super.getSSLContext(sslConfiguration); + void reloadSSLContext(SSLConfiguration configuration) { + counter.incrementAndGet(); + super.reloadSSLContext(configuration); } }; - final ClientSSLService clientSSLService = new ClientSSLService(settings, env, config) { - @Override - SSLContext getSSLContext(SSLConfiguration sslConfiguration) { - clientCounter.incrementAndGet(); - return super.getSSLContext(sslConfiguration); - } - }; - - final SSLConfigurationReloader reloader = - new SSLConfigurationReloader(settings, env, serverSSLService, clientSSLService, resourceWatcherService); final X509ExtendedKeyManager keyManager; - final X509ExtendedKeyManager[] originalKeyManagers; if (checkKeys) { - originalKeyManagers = config.keyConfig().keyManagers(env); - assertThat(originalKeyManagers.length, is(1)); - keyManager = ((ReloadableX509KeyManager) originalKeyManagers[0]).getKeyManager(); + keyManager = sslService.sslContextHolder(config).keyManager().getKeyManager(); } else { - originalKeyManagers = null; keyManager = null; } - final X509ExtendedTrustManager[] originalTrustManagers; final X509ExtendedTrustManager trustManager; if (checkTrust) { - originalTrustManagers = config.trustConfig().trustManagers(env); - assertThat(originalTrustManagers.length, is(1)); - trustManager = ((ReloadableTrustManager) originalTrustManagers[0]).getTrustManager(); + trustManager = sslService.sslContextHolder(config).trustManager().getTrustManager(); } else { - originalTrustManagers = null; trustManager = null; } - // register configuration with reloader - reloader.onSSLContextLoaded(config); - // key manager checks if (checkKeys) { - assertKeyManagersSame(keyManager, config.keyConfig().keyManagers(env)); keyManagerPreChecks.apply(keyManager, config); } // trust manager checks if (checkTrust) { - assertTrustManagersSame(trustManager, config.trustConfig().trustManagers(env)); trustManagerPreChecks.apply(trustManager, config); } - assertEquals(0, clientSSLService.getLoadedSSLConfigurations().size()); - assertEquals(0, serverSSLService.getLoadedSSLConfigurations().size()); - assertEquals("nothing should have called get", 0, clientCounter.get()); - assertEquals("nothing should have called get", 0, serverCounter.get()); + assertEquals("nothing should have called get", 0, counter.get()); // modify modificationFunction.run(); - assertTrue(awaitBusy(() -> clientCounter.get() > 0 && serverCounter.get() > 0)); + assertTrue(awaitBusy(() -> counter.get() > 0)); // check key manager if (checkKeys) { - final X509ExtendedKeyManager[] updatedKeyManagers = config.keyConfig().keyManagers(env); - assertThat(updatedKeyManagers, sameInstance(originalKeyManagers)); - final X509ExtendedKeyManager updatedKeyManager = ((ReloadableX509KeyManager) updatedKeyManagers[0]).getKeyManager(); + final X509ExtendedKeyManager updatedKeyManager = sslService.sslContextHolder(config).keyManager().getKeyManager(); + assertThat(updatedKeyManager, not(sameInstance(keyManager))); keyManagerPostChecks.apply(updatedKeyManager, config); } // check trust manager if (checkTrust) { - final X509ExtendedTrustManager[] updatedTrustManagers = config.trustConfig().trustManagers(env); - assertThat(updatedTrustManagers, sameInstance(originalTrustManagers)); - final X509ExtendedTrustManager updatedTrustManager = ((ReloadableTrustManager) updatedTrustManagers[0]).getTrustManager(); + final X509ExtendedTrustManager updatedTrustManager = sslService.sslContextHolder(config).trustManager().getTrustManager(); assertThat(updatedTrustManager, not(sameInstance(trustManager))); trustManagerPostChecks.apply(updatedTrustManager, config); } } - private void assertContainsCertificateWithMatchingName(Certificate[] certificates, Matcher matcher) { - for (Certificate certificate : certificates) { - if (certificate instanceof X509Certificate) { - if (matcher.matches(((X509Certificate) certificate).getSubjectX500Principal().getName())) { - return; - } - } - } - fail("no matching certificate could be found"); - } - - private void assertKeyManagersSame(X509ExtendedKeyManager original, X509ExtendedKeyManager[] other) { - assertEquals(1, other.length); - assertThat(other[0], instanceOf(ReloadableX509KeyManager.class)); - X509ExtendedKeyManager otherKeyManager = ((ReloadableX509KeyManager) other[0]).getKeyManager(); - assertThat(otherKeyManager, sameInstance(original)); - } - - private void assertTrustManagersSame(X509ExtendedTrustManager original, X509ExtendedTrustManager[] other) { - assertEquals(1, other.length); - assertThat(other[0], instanceOf(ReloadableTrustManager.class)); - X509ExtendedTrustManager otherTrustManager = ((ReloadableTrustManager) other[0]).getTrustManager(); - assertThat(otherTrustManager, sameInstance(original)); - } - private static void atomicMoveIfPossible(Path source, Path target) throws IOException { try { Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java index 5f417c0a5b2..6531d62f823 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java @@ -21,8 +21,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; public class SSLConfigurationTests extends ESTestCase { @@ -44,24 +42,6 @@ public class SSLConfigurationTests extends ESTestCase { assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL))); } - public void testThatSSLConfigurationWithoutAutoGenHasCorrectDefaults() { - SSLConfiguration globalSettings = new Global(Settings.EMPTY); - SSLConfiguration scopedSettings = new Custom(Settings.EMPTY, globalSettings); - for (SSLConfiguration sslConfiguration : Arrays.asList(globalSettings, scopedSettings)) { - assertThat(sslConfiguration.keyConfig(), sameInstance(KeyConfig.NONE)); - assertThat(sslConfiguration.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE))); - assertThat(sslConfiguration.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT))); - assertThat(sslConfiguration.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL))); - assertThat(sslConfiguration.trustConfig(), notNullValue()); - assertThat(sslConfiguration.trustConfig(), is(instanceOf(StoreTrustConfig.class))); - - StoreTrustConfig ksTrustInfo = (StoreTrustConfig) sslConfiguration.trustConfig(); - assertThat(ksTrustInfo.trustStorePath, is(nullValue())); - assertThat(ksTrustInfo.trustStorePassword, is(nullValue())); - assertThat(ksTrustInfo.trustStoreAlgorithm, is(nullValue())); - } - } - public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() { Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", "path") @@ -246,11 +226,11 @@ public class SSLConfigurationTests extends ESTestCase { SSLConfiguration config = new Global(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig(); - KeyManager[] keyManagers = keyConfig.keyManagers(env); - assertThat(keyManagers.length, is(1)); + KeyManager keyManager = keyConfig.createKeyManager(env); + assertNotNull(keyManager); assertThat(config.trustConfig(), sameInstance(keyConfig)); - TrustManager[] trustManagers = keyConfig.trustManagers(env); - assertThat(trustManagers.length, is(1)); + TrustManager trustManager = keyConfig.createTrustManager(env); + assertNotNull(trustManager); } public void testConfigurationUsingPEMKeyAndTrustFiles() { @@ -269,11 +249,11 @@ public class SSLConfigurationTests extends ESTestCase { SSLConfiguration config = new Global(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig(); - KeyManager[] keyManagers = keyConfig.keyManagers(env); - assertThat(keyManagers.length, is(1)); + KeyManager keyManager = keyConfig.createKeyManager(env); + assertNotNull(keyManager); assertThat(config.trustConfig(), not(sameInstance(keyConfig))); assertThat(config.trustConfig(), instanceOf(PEMTrustConfig.class)); - TrustManager[] trustManagers = keyConfig.trustManagers(env); - assertThat(trustManagers.length, is(1)); + TrustManager trustManager = keyConfig.createTrustManager(env); + assertNotNull(trustManager); } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java index 9301b3d4739..6ff302e1ad0 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java @@ -19,6 +19,7 @@ import org.elasticsearch.common.network.InetAddressHelper; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.util.set.Sets; +import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecuritySettingsSource; @@ -104,13 +105,14 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { } Settings settings = Settings.builder() - .put("keystore.path", keystorePath) - .put("keystore.password", "changeme") - .put("truststore.path", nodeStorePath) - .put("truststore.password", "testnode") + .put("path.home", createTempDir()) + .put("xpack.security.ssl.keystore.path", keystorePath) + .put("xpack.security.ssl.keystore.password", "changeme") + .put("xpack.security.ssl.truststore.path", nodeStorePath) + .put("xpack.security.ssl.truststore.password", "testnode") .build(); String node = randomFrom(internalCluster().getNodeNames()); - ServerSSLService sslService = internalCluster().getInstance(ServerSSLService.class, node); + SSLService sslService = new SSLService(settings, new Environment(settings)); SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(settings); InetSocketTransportAddress address = (InetSocketTransportAddress) internalCluster() .getInstance(Transport.class, node).boundAddress().publishAddress(); @@ -119,6 +121,7 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { socket.startHandshake(); fail("handshake should not have been successful!"); } catch (SSLHandshakeException | SocketException expected) { + logger.trace("expected exception", expected); } KeyStore nodeStore = KeyStore.getInstance("jks"); @@ -139,6 +142,7 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { CountDownLatch latch = new CountDownLatch(1); assertBusy(() -> { try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) { + logger.info("opened socket for reloading [{}]", socket); socket.addHandshakeCompletedListener(event -> { try { assertThat(event.getPeerPrincipal().getName(), containsString("Test Node")); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ClientSSLServiceTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java similarity index 57% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ClientSSLServiceTests.java rename to elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java index 826c2e42699..a4fc145d4c9 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ClientSSLServiceTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java @@ -9,12 +9,13 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; +import org.elasticsearch.test.junit.annotations.Network; import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.test.junit.annotations.Network; import org.junit.Before; import javax.net.ssl.SSLContext; @@ -39,28 +40,29 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; -public class ClientSSLServiceTests extends ESTestCase { +public class SSLServiceTests extends ESTestCase { - private Environment env; + private Path testnodeStore; private Path testclientStore; + private Environment env; @Before public void setup() throws Exception { + testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); testclientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"); - env = randomBoolean() ? new Environment(Settings.builder().put("path.home", createTempDir()).build()) : null; + env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); } public void testThatInvalidProtocolThrowsException() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.protocol", "non-existing") + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.security.ssl.truststore.path", testnodeStore) + .put("xpack.security.ssl.truststore.password", "testnode") + .build(); try { - Settings settings = Settings.builder() - .put("xpack.security.ssl.protocol", "non-existing") - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .put("xpack.security.ssl.truststore.path", testclientStore) - .put("xpack.security.ssl.truststore.password", "testclient") - .build(); - ClientSSLService clientSSLService = new ClientSSLService(settings, null, new Global(settings)); - clientSSLService.createSSLEngine(); + new SSLService(settings, env); fail("expected an exception"); } catch (ElasticsearchException e) { assertThat(e.getMessage(), containsString("failed to initialize the SSLContext")); @@ -68,29 +70,34 @@ public class ClientSSLServiceTests extends ESTestCase { } public void testThatCustomTruststoreCanBeSpecified() throws Exception { - Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); + Path testClientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"); - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .put("transport.profiles.foo.xpack.security.ssl.truststore.path", testClientStore) + .put("transport.profiles.foo.xpack.security.ssl.truststore.password", "testclient") + .build(); + SSLService sslService = new SSLService(settings, env); - Settings.Builder settingsBuilder = Settings.builder() - .put("truststore.path", testnodeStore) - .put("truststore.password", "testnode"); + Settings customTruststoreSettings = Settings.builder() + .put("ssl.truststore.path", testClientStore) + .put("ssl.truststore.password", "testclient") + .build(); - SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(settingsBuilder.build()); + SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings); assertThat(sslEngineWithTruststore, is(not(nullValue()))); - SSLEngine sslEngine = sslService.createSSLEngine(); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); assertThat(sslEngineWithTruststore, is(not(sameInstance(sslEngine)))); } public void testThatSslContextCachingWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); SSLContext sslContext = sslService.sslContext(); SSLContext cachedSslContext = sslService.sslContext(); @@ -101,21 +108,23 @@ public class ClientSSLServiceTests extends ESTestCase { public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception { Path differentPasswordsStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); - createClientSSLService(Settings.builder() + Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", differentPasswordsStore) .put("xpack.security.ssl.keystore.password", "testnode") .put("xpack.security.ssl.keystore.key_password", "testnode1") - .build()).createSSLEngine(); + .build(); + new SSLService(settings, env).createSSLEngine(Settings.EMPTY); } public void testIncorrectKeyPasswordThrowsException() throws Exception { Path differentPasswordsStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); try { - createClientSSLService(Settings.builder() + Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", differentPasswordsStore) .put("xpack.security.ssl.keystore.password", "testnode") - .build()).createSSLEngine(); + .build(); + new SSLService(settings, env).createSSLEngine(Settings.EMPTY); fail("expected an exception"); } catch (ElasticsearchException e) { assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory")); @@ -123,63 +132,145 @@ public class ClientSSLServiceTests extends ESTestCase { } public void testThatSSLv3IsNotEnabled() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); - SSLEngine engine = sslService.createSSLEngine(); + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3"))); } public void testThatSSLSessionCacheHasDefaultLimits() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); SSLSessionContext context = sslService.sslContext().getServerSessionContext(); assertThat(context.getSessionCacheSize(), equalTo(1000)); assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds())); } public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") .put("xpack.security.ssl.session.cache_size", "300") .put("xpack.security.ssl.session.cache_timeout", "600s") - .build()); + .build(); + SSLService sslService = new SSLService(settings, env); SSLSessionContext context = sslService.sslContext().getServerSessionContext(); assertThat(context.getSessionCacheSize(), equalTo(300)); assertThat(context.getSessionTimeout(), equalTo(600)); } + public void testCreateWithoutAnySettingsNotValidForServer() throws Exception { + SSLService sslService = new SSLService(Settings.EMPTY, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY)); + } + + public void testCreateWithOnlyTruststoreNotValidForServer() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", testnodeStore) + .put("xpack.security.ssl.truststore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY)); + } + + public void testCreateWithKeystoreIsValidForServer() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY)); + } + public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.EMPTY); - SSLEngine sslEngine = sslService.createSSLEngine(); + SSLService sslService = new SSLService(Settings.EMPTY, env); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); assertThat(sslEngine, notNullValue()); } public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() + Settings settings = Settings.builder() .put("xpack.security.ssl.truststore.path", testclientStore) .put("xpack.security.ssl.truststore.password", "testclient") - .build()); - SSLEngine sslEngine = sslService.createSSLEngine(); + .build(); + SSLService sslService = new SSLService(settings, env); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); assertThat(sslEngine, notNullValue()); } - public void testThatCreateSSLEngineWithOnlyKeystoreWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); - SSLEngine sslEngine = sslService.createSSLEngine(); - assertThat(sslEngine, notNullValue()); + public void testThatTruststorePasswordIsRequired() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.security.ssl.truststore.path", testnodeStore) + .build(); + IllegalArgumentException e = + expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("no truststore password configured")); + } + + public void testThatKeystorePasswordIsRequired() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .build(); + IllegalArgumentException e = + expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("no keystore password configured")); + } + + public void testCiphersAndInvalidCiphersWork() throws Exception { + List ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS); + ciphers.add("foo"); + ciphers.add("bar"); + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .putArray("xpack.security.ssl.ciphers", ciphers.toArray(new String[ciphers.size()])) + .build(); + SSLService sslService = new SSLService(settings, env); + SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); + assertThat(engine, is(notNullValue())); + String[] enabledCiphers = engine.getEnabledCipherSuites(); + assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar"))); + } + + public void testInvalidCiphersOnlyThrowsException() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .putArray("xpack.security.ssl.ciphers", new String[] { "foo", "bar" }) + .build(); + IllegalArgumentException e = + expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("none of the ciphers [foo, bar] are supported by this JVM")); + } + + public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.security.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY); + SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY); + final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), config.ciphers(), false); + assertThat(factory.getDefaultCipherSuites(), is(ciphers)); + + try (SSLSocket socket = (SSLSocket) factory.createSocket()) { + assertThat(socket.getEnabledCipherSuites(), is(ciphers)); + assertThat(socket.getEnabledProtocols(), is(config.supportedProtocols().toArray(Strings.EMPTY_ARRAY))); + } } @Network public void testThatSSLContextWithoutSettingsWorks() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.EMPTY); + SSLService sslService = new SSLService(Settings.EMPTY, env); 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 @@ -191,23 +282,23 @@ public class ClientSSLServiceTests extends ESTestCase { @Network public void testThatSSLContextTrustsJDKTrustedCAs() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() + Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", testclientStore) .put("xpack.security.ssl.keystore.password", "testclient") - .build()); - SSLContext sslContext = sslService.sslContext(); + .build(); + SSLContext sslContext = new SSLService(settings, env).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 which will succeed because the JDK // certs are trusted by default client.execute(new HttpGet("https://www.elastic.co/")).close(); } - sslService = createClientSSLService(Settings.builder() + settings = Settings.builder() .put("xpack.security.ssl.keystore.path", testclientStore) .put("xpack.security.ssl.keystore.password", "testclient") .put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), "false") - .build()); - sslContext = sslService.sslContext(); + .build(); + sslContext = new SSLService(settings, env).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 @@ -218,72 +309,4 @@ public class ClientSSLServiceTests extends ESTestCase { assertThat(e, instanceOf(SSLHandshakeException.class)); } } - - public void testThatTruststorePasswordIsRequired() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.truststore.path", testclientStore) - .build()); - try { - sslService.sslContext(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("no truststore password configured")); - } - } - - public void testThatKeystorePasswordIsRequired() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .build()); - try { - sslService.sslContext(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("no keystore password configured")); - } - } - - public void testValidCiphersAndInvalidCiphersWork() throws Exception { - List ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS); - ciphers.add("foo"); - ciphers.add("bar"); - ClientSSLService sslService = createClientSSLService(Settings.builder() - .putArray("xpack.security.ssl.ciphers", ciphers.toArray(new String[ciphers.size()])) - .build()); - SSLEngine engine = sslService.createSSLEngine(); - assertThat(engine, is(notNullValue())); - String[] enabledCiphers = engine.getEnabledCipherSuites(); - assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar"))); - } - - public void testInvalidCiphersOnlyThrowsException() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .putArray("xpack.security.ssl.ciphers", new String[] { "foo", "bar" }) - .build()); - try { - sslService.createSSLEngine(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("none of the ciphers [foo, bar] are supported by this JVM")); - } - } - - public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception { - ClientSSLService sslService = createClientSSLService(Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") - .build()); - SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY); - final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers(), false); - assertThat(factory.getDefaultCipherSuites(), is(ciphers)); - - try (SSLSocket socket = (SSLSocket) factory.createSocket()) { - assertThat(socket.getEnabledCipherSuites(), is(ciphers)); - assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols())); - } - } - - private ClientSSLService createClientSSLService(Settings settings) { - return new ClientSSLService(settings, env, new Global(settings)); - } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ServerSSLServiceTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ServerSSLServiceTests.java deleted file mode 100644 index d179604291f..00000000000 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/ServerSSLServiceTests.java +++ /dev/null @@ -1,254 +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.xpack.security.ssl; - -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.test.ESTestCase; -import org.junit.Before; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSessionContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.sameInstance; - -public class ServerSSLServiceTests extends ESTestCase { - - private Path testnodeStore; - private Environment env; - - @Before - public void setup() throws Exception { - testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); - env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - } - - public void testThatInvalidProtocolThrowsException() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.protocol", "non-existing") - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .put("xpack.security.ssl.truststore.path", testnodeStore) - .put("xpack.security.ssl.truststore.password", "testnode") - .build(); - try { - new ServerSSLService(settings, env, new Global(settings)).createSSLEngine(); - fail("expected an exception"); - } catch (ElasticsearchException e) { - assertThat(e.getMessage(), containsString("failed to initialize the SSLContext")); - } - } - - public void testThatCustomTruststoreCanBeSpecified() throws Exception { - Path testClientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"); - - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - - Settings.Builder settingsBuilder = Settings.builder() - .put("truststore.path", testClientStore) - .put("truststore.password", "testclient"); - - SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(settingsBuilder.build()); - assertThat(sslEngineWithTruststore, is(not(nullValue()))); - - SSLEngine sslEngine = sslService.createSSLEngine(); - assertThat(sslEngineWithTruststore, is(not(sameInstance(sslEngine)))); - } - - public void testThatSslContextCachingWorks() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - - SSLContext sslContext = sslService.sslContext(); - SSLContext cachedSslContext = sslService.sslContext(); - - assertThat(sslContext, is(sameInstance(cachedSslContext))); - } - - public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception { - Path differentPasswordsStore = - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", differentPasswordsStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .put("xpack.security.ssl.keystore.key_password", "testnode1") - .build(); - new ServerSSLService(settings, env, new Global(settings)).createSSLEngine(); - } - - public void testIncorrectKeyPasswordThrowsException() throws Exception { - Path differentPasswordsStore = - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); - try { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", differentPasswordsStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - new ServerSSLService(settings, env, new Global(settings)).createSSLEngine(); - fail("expected an exception"); - } catch (ElasticsearchException e) { - assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory")); - } - } - - public void testThatSSLv3IsNotEnabled() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - SSLEngine engine = sslService.createSSLEngine(); - assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3"))); - } - - public void testThatSSLSessionCacheHasDefaultLimits() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - SSLSessionContext context = sslService.sslContext().getServerSessionContext(); - assertThat(context.getSessionCacheSize(), equalTo(1000)); - assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds())); - } - - public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .put("xpack.security.ssl.session.cache_size", "300") - .put("xpack.security.ssl.session.cache_timeout", "600s") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - SSLSessionContext context = sslService.sslContext().getServerSessionContext(); - assertThat(context.getSessionCacheSize(), equalTo(300)); - assertThat(context.getSessionTimeout(), equalTo(600)); - } - - public void testThatCreateSSLEngineWithoutAnySettingsDoesNotWork() throws Exception { - ServerSSLService sslService = new ServerSSLService(Settings.EMPTY, env, new Global(Settings.EMPTY)); - try { - sslService.createSSLEngine(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("a key must be configured to act as a server")); - } - } - - public void testThatCreateSSLEngineWithOnlyTruststoreDoesNotWork() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", testnodeStore) - .put("xpack.security.ssl.truststore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - try { - sslService.createSSLEngine(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("a key must be configured to act as a server")); - } - } - - public void testThatTruststorePasswordIsRequired() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .put("xpack.security.ssl.truststore.path", testnodeStore) - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - try { - sslService.sslContext(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("no truststore password configured")); - } - } - - public void testThatKeystorePasswordIsRequired() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - try { - sslService.sslContext(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("no keystore password configured")); - } - } - - public void testCiphersAndInvalidCiphersWork() throws Exception { - List ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS); - ciphers.add("foo"); - ciphers.add("bar"); - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .putArray("xpack.security.ssl.ciphers", ciphers.toArray(new String[ciphers.size()])) - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - SSLEngine engine = sslService.createSSLEngine(); - assertThat(engine, is(notNullValue())); - String[] enabledCiphers = engine.getEnabledCipherSuites(); - assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar"))); - } - - public void testInvalidCiphersOnlyThrowsException() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .putArray("xpack.security.ssl.ciphers", new String[] { "foo", "bar" }) - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - try { - sslService.createSSLEngine(); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("none of the ciphers [foo, bar] are supported by this JVM")); - } - } - - public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception { - Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") - .build(); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY); - final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers(), false); - assertThat(factory.getDefaultCipherSuites(), is(ciphers)); - - try (SSLSocket socket = (SSLSocket) factory.createSocket()) { - assertThat(socket.getEnabledCipherSuites(), is(ciphers)); - assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols())); - } - } -} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/Netty3HandshakeWaitingHandlerTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/Netty3HandshakeWaitingHandlerTests.java index 6f6edf6fbea..96d05ffc8d2 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/Netty3HandshakeWaitingHandlerTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/Netty3HandshakeWaitingHandlerTests.java @@ -8,9 +8,8 @@ package org.elasticsearch.xpack.security.transport.netty3; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; @@ -30,7 +29,6 @@ import org.jboss.netty.handler.ssl.SslHandler; import org.junit.After; import org.junit.Before; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import java.io.PrintWriter; @@ -60,7 +58,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { private ServerBootstrap serverBootstrap; private ClientBootstrap clientBootstrap; - private SSLContext sslContext; + private SSLService sslService; private final AtomicReference failureCause = new AtomicReference<>(); private ExecutorService threadPoolExecutor; @@ -76,9 +74,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { .put("xpack.security.ssl.keystore.password", "testnode") .build(); Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings)); - - sslContext = sslService.sslContext(); + sslService = new SSLService(settings, env); startBootstrap(); @@ -104,7 +100,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine engine = sslContext.createSSLEngine(); + final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); engine.setUseClientMode(true); return Channels.pipeline( new SslHandler(engine)); @@ -141,7 +137,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine engine = sslContext.createSSLEngine(); + final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); engine.setUseClientMode(true); return Channels.pipeline( new SslHandler(engine), @@ -212,7 +208,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { return new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine sslEngine = sslContext.createSSLEngine(); + final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); sslEngine.setUseClientMode(false); return Channels.pipeline(new SslHandler(sslEngine), new SimpleChannelHandler() { diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransportTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransportTests.java index e81725bb5ec..f5d08ddbb3f 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransportTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3HttpServerTransportTests.java @@ -11,8 +11,7 @@ import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.env.Environment; import org.elasticsearch.http.HttpTransportSettings; import org.elasticsearch.http.netty3.Netty3HttpMockUtil; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.test.ESTestCase; @@ -26,6 +25,7 @@ import java.nio.file.Path; import java.util.Locale; import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; @@ -33,7 +33,8 @@ import static org.mockito.Mockito.mock; public class SecurityNetty3HttpServerTransportTests extends ESTestCase { - private ServerSSLService serverSSLService; + private SSLService sslService; + private Environment env; @Before public void createSSLService() throws Exception { @@ -41,15 +42,16 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", testnodeStore) .put("xpack.security.ssl.keystore.password", "testnode") + .put("path.home", createTempDir()) .build(); - Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - serverSSLService = new ServerSSLService(settings, env, new Global(settings)); + env = new Environment(settings); + sslService = new SSLService(settings, env); } public void testDefaultClientAuth() throws Exception { Settings settings = Settings.builder().put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -62,7 +64,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -75,7 +77,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); @@ -88,7 +90,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -99,17 +101,19 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); SSLEngine defaultEngine = factory.getPipeline().get(SslHandler.class).getEngine(); settings = Settings.builder() + .put(env.settings()) .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) .put("xpack.security.http.ssl.supported_protocols", "TLSv1.2") .build(); + sslService = new SSLService(settings, new Environment(settings)); transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); factory = transport.configureServerChannelPipelineFactory(); SSLEngine customEngine = factory.getPipeline().get(SslHandler.class).getEngine(); @@ -144,4 +148,34 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); assertThat(pluginSettingsBuilder.build().isEmpty(), is(true)); } + + public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, transport::configureServerChannelPipelineFactory); + assertThat(e.getMessage(), containsString("key must be provided")); + } + + public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); + assertNotNull(transport.configureServerChannelPipelineFactory()); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3TransportTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3TransportTests.java index 22a4b86da80..81e4de857df 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3TransportTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SecurityNetty3TransportTests.java @@ -11,9 +11,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.env.Environment; import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; @@ -25,14 +23,16 @@ import org.junit.Before; import java.nio.file.Path; import java.util.Locale; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.mock; public class SecurityNetty3TransportTests extends ESTestCase { - private ServerSSLService serverSSLService; - private ClientSSLService clientSSLService; + + private Environment env; + private SSLService sslService; @Before public void createSSLService() throws Exception { @@ -41,16 +41,14 @@ public class SecurityNetty3TransportTests extends ESTestCase { .put("xpack.security.ssl.keystore.path", testnodeStore) .put("xpack.security.ssl.keystore.password", "testnode") .build(); - Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - Global globalSSLConfiguration = new Global(settings); - serverSSLService = new ServerSSLService(settings, env, globalSSLConfiguration); - clientSSLService = new ClientSSLService(settings, env, globalSSLConfiguration); + env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); + sslService = new SSLService(settings, env); } public void testThatSSLCanBeDisabledByProfile() throws Exception { Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", @@ -61,7 +59,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void testThatSSLCanBeEnabledByProfile() throws Exception { Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), false).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", @@ -72,7 +70,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void testThatProfileTakesDefaultSSLSetting() throws Exception { Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); @@ -82,7 +80,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void testDefaultClientAuth() throws Exception { Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); @@ -96,7 +94,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); @@ -110,7 +108,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); @@ -124,7 +122,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY); @@ -136,7 +134,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE"); Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", @@ -149,7 +147,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), - mock(BigArrays.class), null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class), + mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", @@ -162,7 +160,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), - mock(NetworkService.class), mock(BigArrays.class), null, serverSSLService, clientSSLService, + mock(NetworkService.class), mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", @@ -170,4 +168,38 @@ public class SecurityNetty3TransportTests extends ESTestCase { assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(true)); } + + public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), + mock(NetworkService.class), mock(BigArrays.class), null, sslService, + mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> transport.configureServerChannelPipelineFactory(randomAsciiOfLength(6), Settings.EMPTY)); + assertThat(e.getMessage(), containsString("key must be provided")); + } + + public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty3Transport.SSL_SETTING.getKey(), false) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), + mock(NetworkService.class), mock(BigArrays.class), null, sslService, + mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); + assertNotNull(transport.configureServerChannelPipelineFactory(randomAsciiOfLength(6), Settings.EMPTY)); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java index 0fffdf7acaa..3b81dcf2d1c 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java @@ -16,8 +16,7 @@ import org.elasticsearch.http.HttpTransportSettings; import org.elasticsearch.http.netty4.Netty4HttpMockUtil; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.junit.Before; @@ -28,6 +27,7 @@ import java.nio.file.Path; import java.util.Locale; import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; @@ -35,7 +35,8 @@ import static org.mockito.Mockito.mock; public class SecurityNetty4HttpServerTransportTests extends ESTestCase { - private ServerSSLService serverSSLService; + private SSLService sslService; + private Environment env; @Before public void createSSLService() throws Exception { @@ -43,15 +44,16 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", testNodeStore) .put("xpack.security.ssl.keystore.password", "testnode") + .put("path.home", createTempDir()) .build(); - Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - serverSSLService = new ServerSSLService(settings, env, new Global(settings)); + env = new Environment(settings); + sslService = new SSLService(settings, env); } public void testDefaultClientAuth() throws Exception { Settings settings = Settings.builder().put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build(); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.configureServerChannelHandler(); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -65,7 +67,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.configureServerChannelHandler(); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -79,7 +81,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.configureServerChannelHandler(); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -93,7 +95,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.configureServerChannelHandler(); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -105,18 +107,20 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build(); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.configureServerChannelHandler(); EmbeddedChannel ch = new EmbeddedChannel(handler); SSLEngine defaultEngine = ch.pipeline().get(SslHandler.class).engine(); settings = Settings.builder() + .put(env.settings()) .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) .put("xpack.security.http.ssl.supported_protocols", "TLSv1.2") .build(); + sslService = new SSLService(settings, new Environment(settings)); transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), - mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); handler = transport.configureServerChannelHandler(); ch = new EmbeddedChannel(handler); @@ -152,4 +156,34 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); assertThat(pluginSettingsBuilder.build().isEmpty(), is(true)); } + + public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, transport::configureServerChannelHandler); + assertThat(e.getMessage(), containsString("key must be provided")); + } + + public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), + mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); + assertNotNull(transport.configureServerChannelHandler()); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java index 7f9266bda1d..bbdb87e180a 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java @@ -17,23 +17,23 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.netty4.Netty4MockUtil; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; -import org.elasticsearch.xpack.security.ssl.ServerSSLService; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.junit.Before; import java.nio.file.Path; import java.util.Locale; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.mock; public class SecurityNetty4TransportTests extends ESTestCase { - private ServerSSLService serverSSLService; - private ClientSSLService clientSSLService; + + private Environment env; + private SSLService sslService; @Before public void createSSLService() throws Exception { @@ -41,11 +41,10 @@ public class SecurityNetty4TransportTests extends ESTestCase { Settings settings = Settings.builder() .put("xpack.security.ssl.keystore.path", testnodeStore) .put("xpack.security.ssl.keystore.password", "testnode") + .put("path.home", createTempDir()) .build(); - Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - Global globalSSLConfiguration = new Global(settings); - serverSSLService = new ServerSSLService(settings, env, globalSSLConfiguration); - clientSSLService = new ClientSSLService(settings, env, globalSSLConfiguration); + env = new Environment(settings); + sslService = new SSLService(settings, env); } private SecurityNetty4Transport createTransport(boolean sslEnabled) { @@ -66,8 +65,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, - serverSSLService, - clientSSLService); + sslService); } public void testThatSSLCanBeDisabledByProfile() throws Exception { @@ -171,4 +169,35 @@ public class SecurityNetty4TransportTests extends ESTestCase { assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true)); } + public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty4Transport.SSL_SETTING.getKey(), true) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = new SecurityNetty4Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), + mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY)); + assertThat(e.getMessage(), containsString("key must be provided")); + } + + public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { + Settings settings = Settings.builder() + .put("xpack.security.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.ssl.truststore.password", "testnode") + .put(SecurityNetty4Transport.SSL_SETTING.getKey(), false) + .put("path.home", createTempDir()) + .build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = new SecurityNetty4Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), + mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService); + assertNotNull(transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY)); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java index fee11261e0e..edb3e7bfe60 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java @@ -22,18 +22,21 @@ import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.XPackTransportClient; import org.elasticsearch.xpack.security.Security; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.security.KeyStore; +import java.security.SecureRandom; import java.security.cert.CertPathBuilderException; -import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -71,11 +74,7 @@ public class SslClientAuthTests extends SecurityIntegTestCase { } public void testThatHttpWorksWithSslClientAuth() throws IOException { - Settings settings = Settings.builder() - .put(getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient")) - .build(); - ClientSSLService sslService = new ClientSSLService(settings, null, new Global(settings)); - SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslService.sslContext(), NoopHostnameVerifier.INSTANCE); + SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(getSSLContext(), NoopHostnameVerifier.INSTANCE); try (RestClient restClient = createRestClient(httpClientBuilder -> httpClientBuilder.setSSLStrategy(sessionStrategy), "https")) { Response response = restClient.performRequest("GET", "/", new BasicHeader("Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword()))); @@ -108,4 +107,21 @@ public class SslClientAuthTests extends SecurityIntegTestCase { assertGreenClusterState(client); } } + + private SSLContext getSSLContext() { + try (InputStream in = + Files.newInputStream(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"))) { + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load(in, "testclient".toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(keyStore, "testclient".toCharArray()); + SSLContext context = SSLContext.getInstance("TLSv1.2"); + context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); + return context; + } catch (Exception e) { + throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); + } + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java index 817a44e0b9d..808f0d63eec 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java @@ -23,8 +23,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.http.HttpServerTransport; -import org.elasticsearch.xpack.security.ssl.ClientSSLService; -import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; +import org.elasticsearch.xpack.security.ssl.SSLService; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; @@ -99,12 +98,14 @@ public class SslIntegrationTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient")) .build(); - ClientSSLService service = new ClientSSLService(settings, null, new Global(settings)); + SSLService service = new SSLService(settings, null); CredentialsProvider provider = new BasicCredentialsProvider(); provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nodeClientUsername(), new String(nodeClientPassword().internalChars()))); - try (CloseableHttpClient client = HttpClients.custom().setSSLContext(service.sslContext()) + try (CloseableHttpClient client = HttpClients.custom() + .setSSLSocketFactory(new SSLConnectionSocketFactory(service.sslSocketFactory(Settings.EMPTY), + SSLConnectionSocketFactory.getDefaultHostnameVerifier())) .setDefaultCredentialsProvider(provider).build(); CloseableHttpResponse response = client.execute(new HttpGet(getNodeUrl()))) { assertThat(response.getStatusLine().getStatusCode(), is(200));