From ad9a7c9b9641683ddaf2030a609947d5cd9f9e1a Mon Sep 17 00:00:00 2001 From: jaymode Date: Thu, 1 Sep 2016 10:51:41 -0400 Subject: [PATCH] Migrate xpack to use the common ssl configuration This change migrates xpack (security, watcher, and monitoring) to use the common ssl configuration for the elastic stack. As part of this work, several aspects of how we deal with SSL has been modified. From a functionality perspective, an xpack wide configuration for SSL was added and all of the code that needs SSL uses the SSLService now. The following is a list of all of the aspects of xpack that can have their own SSL configuration, which are separate from the xpack wide configuration: * Transport * Transport profiles * HTTP Transport * Realms * Monitoring Exporters * HTTP Client In terms of the code, some cleanups were made with these changes. SSLConfiguration is now a concrete class and SSLConfiguration.Custom and SSLConfiguration.Global have been removed. The validate method on key and trust configurations has been removed and these classes will now throw exceptions when they are constructed with bad values. The OptionalSettings helper class has been removed as it was just a file with one line functions that made the code harder to understand. The SSL configuration and service classes have been moved from the security source directories to the main xpack source set. The SSLService now handles more of the configuration of the SSLEngine it returns to prevent callers from having to handle those aspects. The settings that get registered for SSL have been moved to XPackSettings. Also included in this PR is a update to the docs around SSL. This includes a large simplification to the documentation in that the certificate authority configuration section has been removed and the process that is documented for generating certificates only includes the CLI tool that we bundle. Closes elastic/elasticsearch#3104 Closes elastic/elasticsearch#2971 Closes elastic/elasticsearch#3164 Original commit: elastic/x-pack-elasticsearch@5bd9e5ef38b423dd1e1d9ea6d4d4179637b2df8b --- .../qa/smoke-test-plugins-ssl/build.gradle | 4 +- .../SmokeTestMonitoringWithSecurityIT.java | 7 +- .../xpack/monitoring/Monitoring.java | 7 +- .../agent/exporter/http/HttpExporter.java | 79 +--- .../http/HttpExporterSimpleTests.java | 11 +- .../MonitoringSettingsFilterTests.java | 10 +- .../x-pack/security/bin/x-pack/certgen | 2 +- .../x-pack/security/bin/x-pack/certgen.bat | Bin 345 -> 336 bytes .../xpack/security/Security.java | 29 +- .../xpack/security/SecurityFeatureSet.java | 11 +- .../activedirectory/ActiveDirectoryRealm.java | 2 +- .../ActiveDirectorySessionFactory.java | 2 +- .../esnative/ESNativeRealmMigrateTool.java | 2 +- .../xpack/security/authc/ldap/LdapRealm.java | 2 +- .../authc/ldap/LdapSessionFactory.java | 2 +- .../ldap/LdapUserSearchSessionFactory.java | 2 +- .../authc/ldap/support/SessionFactory.java | 2 +- .../xpack/security/authc/pki/PkiRealm.java | 147 +++--- .../security/rest/SecurityRestFilter.java | 13 +- .../xpack/security/ssl/SSLConfiguration.java | 447 ------------------ .../xpack/security/ssl/TrustConfig.java | 156 ------ .../security/support/OptionalSettings.java | 51 -- .../SecurityServerTransportService.java | 40 +- .../SecurityNetty3HttpServerTransport.java | 48 +- .../netty3/SecurityNetty3Transport.java | 154 ++---- .../SecurityNetty4HttpServerTransport.java | 46 +- .../netty4/SecurityNetty4Transport.java | 158 ++----- .../ldap/AbstractAdLdapRealmTestCase.java | 12 +- .../test/SecurityIntegTestCase.java | 4 +- .../test/SecuritySettingsSource.java | 70 ++- .../test/SettingsFilterTests.java | 42 +- .../security/SecurityFeatureSetTests.java | 6 +- .../xpack/security/SecurityTests.java | 3 +- .../audit/index/IndexAuditTrailTests.java | 2 +- .../xpack/security/authc/RunAsIntegTests.java | 3 +- .../AbstractActiveDirectoryIntegTests.java | 6 +- .../ActiveDirectoryGroupsResolverTests.java | 2 +- .../esnative/ESNativeMigrateToolTests.java | 2 +- .../authc/ldap/GroupsResolverTestCase.java | 6 +- .../LdapUserSearchSessionFactoryTests.java | 6 +- .../security/authc/ldap/OpenLdapTests.java | 6 +- .../SessionFactoryLoadBalancingTests.java | 2 +- .../authc/pki/PkiAuthenticationTests.java | 11 +- .../authc/pki/PkiOptionalClientAuthTests.java | 12 +- .../security/authc/pki/PkiRealmTests.java | 65 ++- .../PkiWithoutClientAuthenticationTests.java | 89 ---- .../authc/pki/PkiWithoutSSLTests.java | 50 -- .../rest/SecurityRestFilterTests.java | 3 +- ...ServerTransportFilterIntegrationTests.java | 8 +- .../transport/TransportFilterTests.java | 4 +- .../netty3/IPHostnameVerificationTests.java | 30 +- .../Netty3HandshakeWaitingHandlerTests.java | 12 +- ...ecurityNetty3HttpServerTransportTests.java | 55 ++- .../netty3/SecurityNetty3TransportTests.java | 123 +++-- .../netty3/SslHostnameVerificationTests.java | 28 +- ...ecurityNetty4HttpServerTransportTests.java | 58 ++- .../netty4/SecurityNetty4TransportTests.java | 121 +++-- .../transport/ssl/SslIntegrationTests.java | 9 +- .../transport/ssl/SslMultiPortTests.java | 67 +-- .../certs/simple/truststore-testnode-only.jks | Bin 2339 -> 1048 bytes .../common/network/InetAddressHelper.java | 0 .../org/elasticsearch/xpack/XPackPlugin.java | 15 +- .../elasticsearch/xpack/XPackSettings.java | 197 +++++++- .../xpack/common/http/HttpClient.java | 162 +------ .../elasticsearch/xpack}/ssl/CertUtils.java | 114 ++++- .../xpack}/ssl/CertificateTool.java | 2 +- .../xpack/ssl/DefaultJDKTrustConfig.java | 128 +++++ .../elasticsearch/xpack}/ssl/KeyConfig.java | 29 +- .../xpack}/ssl/PEMKeyConfig.java | 61 ++- .../xpack}/ssl/PEMTrustConfig.java | 28 +- .../xpack/ssl}/SSLClientAuth.java | 23 +- .../xpack/ssl/SSLConfiguration.java | 295 ++++++++++++ .../xpack}/ssl/SSLConfigurationReloader.java | 4 +- .../elasticsearch/xpack}/ssl/SSLService.java | 279 ++++++++--- .../xpack}/ssl/StoreKeyConfig.java | 40 +- .../xpack}/ssl/StoreTrustConfig.java | 38 +- .../xpack/ssl/TrustAllConfig.java | 89 ++++ .../elasticsearch/xpack/ssl/TrustConfig.java | 46 ++ .../xpack/ssl/VerificationMode.java | 71 +++ .../xpack/common/http/HttpClientTests.java | 73 ++- .../http/HttpConnectionTimeoutTests.java | 14 +- .../common/http/HttpReadTimeoutTests.java | 14 +- .../xpack}/ssl/CertUtilsTests.java | 2 +- .../xpack}/ssl/CertificateToolTests.java | 8 +- .../xpack/ssl/SSLClientAuthTests.java} | 21 +- .../ssl/SSLConfigurationReloaderTests.java | 40 +- .../xpack}/ssl/SSLConfigurationTests.java | 197 ++++---- .../xpack}/ssl/SSLReloadIntegTests.java | 18 +- .../xpack}/ssl/SSLServiceTests.java | 263 +++++------ .../elasticsearch/xpack}/ssl/instances.yml | 0 .../actions/webhook/WebhookActionTests.java | 5 +- .../webhook/WebhookHttpsIntegrationTests.java | 4 +- 92 files changed, 2296 insertions(+), 2335 deletions(-) delete mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java delete mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java delete mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/support/OptionalSettings.java delete mode 100644 elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutClientAuthenticationTests.java delete mode 100644 elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutSSLTests.java rename elasticsearch/x-pack/{security => }/src/main/java/org/elasticsearch/common/network/InetAddressHelper.java (100%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/CertUtils.java (72%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/CertificateTool.java (99%) create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/DefaultJDKTrustConfig.java rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/KeyConfig.java (70%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/PEMKeyConfig.java (64%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/PEMTrustConfig.java (73%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security/transport => src/main/java/org/elasticsearch/xpack/ssl}/SSLClientAuth.java (78%) create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/SSLConfigurationReloader.java (97%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/SSLService.java (68%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/StoreKeyConfig.java (72%) rename elasticsearch/x-pack/{security/src/main/java/org/elasticsearch/xpack/security => src/main/java/org/elasticsearch/xpack}/ssl/StoreTrustConfig.java (70%) create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustAllConfig.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustConfig.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/VerificationMode.java rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/CertUtilsTests.java (99%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/CertificateToolTests.java (98%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java => src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java} (88%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/SSLConfigurationReloaderTests.java (94%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/SSLConfigurationTests.java (50%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/SSLReloadIntegTests.java (92%) rename elasticsearch/x-pack/{security/src/test/java/org/elasticsearch/xpack/security => src/test/java/org/elasticsearch/xpack}/ssl/SSLServiceTests.java (58%) rename elasticsearch/x-pack/{security/src/test/resources/org/elasticsearch/xpack/security => src/test/resources/org/elasticsearch/xpack}/ssl/instances.yml (100%) diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle index 533465d98ba..b6f0c38e5dd 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle +++ b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle @@ -172,8 +172,8 @@ integTest { setting 'xpack.security.transport.ssl.enabled', 'true' setting 'xpack.security.http.ssl.enabled', 'true' - setting 'xpack.security.ssl.keystore.path', nodeKeystore.name - setting 'xpack.security.ssl.keystore.password', 'keypass' + setting 'xpack.ssl.keystore.path', nodeKeystore.name + setting 'xpack.ssl.keystore.password', 'keypass' plugin ':x-plugins:elasticsearch:x-pack' diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestMonitoringWithSecurityIT.java b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestMonitoringWithSecurityIT.java index 0a4d5d89962..a2dc5591856 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestMonitoringWithSecurityIT.java +++ b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestMonitoringWithSecurityIT.java @@ -14,7 +14,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.xpack.security.Security; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.xpack.XPackPlugin; import org.junit.After; @@ -71,9 +70,9 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase { final Settings.Builder builder = Settings.builder() .put(Security.USER_SETTING.getKey(), USER + ":" + PASS) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.keystore.path", clientKeyStore) - .put("xpack.security.ssl.keystore.password", KEYSTORE_PASS); + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.keystore.path", clientKeyStore) + .put("xpack.ssl.keystore.password", KEYSTORE_PASS); if (useSecurity3) { builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3); } else { diff --git a/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java b/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java index 82112058531..f5e27a0094d 100644 --- a/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java +++ b/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java @@ -38,6 +38,7 @@ import org.elasticsearch.xpack.monitoring.rest.action.RestMonitoringBulkAction; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.rest.RestHandler; import org.elasticsearch.xpack.security.InternalClient; +import org.elasticsearch.xpack.ssl.SSLService; import java.util.ArrayList; import java.util.Arrays; @@ -98,7 +99,7 @@ public class Monitoring implements ActionPlugin { } public Collection createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService, - LicenseService licenseService) { + LicenseService licenseService, SSLService sslService) { if (enabled == false || tribeNode) { return Collections.emptyList(); } @@ -107,8 +108,10 @@ public class Monitoring implements ActionPlugin { final MonitoringSettings monitoringSettings = new MonitoringSettings(settings, clusterSettings); final CleanerService cleanerService = new CleanerService(settings, clusterSettings, threadPool, licenseState); + // TODO do exporters and their ssl config really need to be dynamic? https://github.com/elastic/x-plugins/issues/3117 + final SSLService dynamicSSLService = sslService.createDynamicSSLService(); Map exporterFactories = new HashMap<>(); - exporterFactories.put(HttpExporter.TYPE, config -> new HttpExporter(config, env)); + exporterFactories.put(HttpExporter.TYPE, config -> new HttpExporter(config, env, dynamicSSLService)); exporterFactories.put(LocalExporter.TYPE, config -> new LocalExporter(config, client, clusterService, cleanerService)); final Exporters exporters = new Exporters(settings, exporterFactories, clusterService); diff --git a/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporter.java b/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporter.java index 497fcb2c368..d0a89315f33 100644 --- a/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporter.java +++ b/elasticsearch/x-pack/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporter.java @@ -32,14 +32,12 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.resolver.MonitoringIndexNameResolver; import org.elasticsearch.xpack.monitoring.agent.resolver.ResolversRegistry; import org.elasticsearch.xpack.monitoring.support.VersionUtils; +import org.elasticsearch.xpack.ssl.SSLService; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -50,10 +48,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; import java.security.AccessController; -import java.security.KeyStore; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Base64; @@ -106,13 +101,6 @@ public class HttpExporter extends Exporter { */ public static final String PIPELINE_CHECK_TIMEOUT_SETTING = "index.pipeline.master_timeout"; - public static final String SSL_SETTING = "ssl"; - public static final String SSL_PROTOCOL_SETTING = "protocol"; - public static final String SSL_TRUSTSTORE_SETTING = "truststore.path"; - public static final String SSL_TRUSTSTORE_PASSWORD_SETTING = "truststore.password"; - public static final String SSL_TRUSTSTORE_ALGORITHM_SETTING = "truststore.algorithm"; - public static final String SSL_HOSTNAME_VERIFICATION_SETTING = SSL_SETTING + ".hostname_verification"; - /** * Minimum supported version of the remote monitoring cluster. *

@@ -156,7 +144,7 @@ public class HttpExporter extends Exporter { final ConnectionKeepAliveWorker keepAliveWorker; Thread keepAliveThread; - public HttpExporter(Config config, Environment env) { + public HttpExporter(Config config, Environment env, SSLService sslService) { super(config); this.env = env; @@ -174,8 +162,9 @@ public class HttpExporter extends Exporter { keepAlive = config.settings().getAsBoolean(CONNECTION_KEEP_ALIVE_SETTING, true); keepAliveWorker = new ConnectionKeepAliveWorker(); - sslSocketFactory = createSSLSocketFactory(config.settings().getAsSettings(SSL_SETTING)); - hostnameVerification = config.settings().getAsBoolean(SSL_HOSTNAME_VERIFICATION_SETTING, true); + final Settings sslSettings = config.settings().getByPrefix("ssl."); + sslSocketFactory = sslService.sslSocketFactory(sslSettings); + hostnameVerification = sslService.getVerificationMode(sslSettings, Settings.EMPTY).isHostnameVerificationEnabled(); resolvers = new ResolversRegistry(config.settings()); // Checks that required templates are loaded @@ -760,64 +749,6 @@ public class HttpExporter extends Exporter { } } - /** - * SSL Initialization * - */ - public SSLSocketFactory createSSLSocketFactory(Settings settings) { - if (settings.names().isEmpty()) { - logger.trace("no ssl context configured"); - return null; - } - SSLContext sslContext; - // Initialize sslContext - try { - String protocol = settings.get(SSL_PROTOCOL_SETTING, "TLS"); - String trustStore = settings.get(SSL_TRUSTSTORE_SETTING, System.getProperty("javax.net.ssl.trustStore")); - String trustStorePassword = settings.get(SSL_TRUSTSTORE_PASSWORD_SETTING, - System.getProperty("javax.net.ssl.trustStorePassword")); - String trustStoreAlgorithm = settings.get(SSL_TRUSTSTORE_ALGORITHM_SETTING, - System.getProperty("ssl.TrustManagerFactory.algorithm")); - - if (trustStore == null) { - throw new SettingsException("missing required setting [" + SSL_TRUSTSTORE_SETTING + "]"); - } - - if (trustStoreAlgorithm == null) { - trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - } - - logger.debug("using ssl trust store [{}] with algorithm [{}]", trustStore, trustStoreAlgorithm); - - Path trustStorePath = env.configFile().resolve(trustStore); - if (!Files.exists(trustStorePath)) { - throw new SettingsException("could not find trust store file [" + trustStorePath + "]"); - } - - TrustManager[] trustManagers; - try (InputStream trustStoreStream = Files.newInputStream(trustStorePath)) { - // Load TrustStore - KeyStore ks = KeyStore.getInstance("jks"); - ks.load(trustStoreStream, trustStorePassword == null ? null : trustStorePassword.toCharArray()); - - // Initialize a trust manager factory with the trusted store - TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm); - trustFactory.init(ks); - - // Retrieve the trust managers from the factory - trustManagers = trustFactory.getTrustManagers(); - } catch (Exception e) { - throw new RuntimeException("Failed to initialize a TrustManagerFactory", e); - } - - sslContext = SSLContext.getInstance(protocol); - sslContext.init(null, trustManagers, null); - - } catch (Exception e) { - throw new ElasticsearchException("failed to initialize ssl", e); - } - return sslContext.getSocketFactory(); - } - BasicAuth resolveAuth(Settings setting) { String username = setting.get(AUTH_USERNAME_SETTING, null); String password = setting.get(AUTH_PASSWORD_SETTING, null); diff --git a/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporterSimpleTests.java b/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporterSimpleTests.java index b4d29f024e1..377df5cfa63 100644 --- a/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporterSimpleTests.java +++ b/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/agent/exporter/http/HttpExporterSimpleTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter; +import org.elasticsearch.xpack.ssl.SSLService; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; @@ -37,7 +38,7 @@ public class HttpExporterSimpleTests extends ESTestCase { final Exporter.Config config = createConfig("_http", builder.build()); final SettingsException exception = expectThrows(SettingsException.class, () -> { - new HttpExporter(config, environment); + new HttpExporter(config, environment, new SSLService(builder.build(), environment)); }); assertThat(exception.getMessage(), equalTo(expected)); @@ -58,7 +59,7 @@ public class HttpExporterSimpleTests extends ESTestCase { final Exporter.Config config = createConfig("_http", builder.build()); final SettingsException exception = expectThrows(SettingsException.class, () -> { - new HttpExporter(config, environment); + new HttpExporter(config, environment, new SSLService(builder.build(), environment)); }); assertThat(exception.getMessage(), equalTo(expected)); @@ -80,7 +81,7 @@ public class HttpExporterSimpleTests extends ESTestCase { final Exporter.Config config = createConfig("_http", builder.build()); final SettingsException exception = expectThrows(SettingsException.class, () -> { - new HttpExporter(config, environment); + new HttpExporter(config, environment, new SSLService(builder.build(), environment)); }); assertThat(exception.getMessage(), equalTo("missing required setting [xpack.monitoring.exporters._http.host]")); @@ -106,7 +107,7 @@ public class HttpExporterSimpleTests extends ESTestCase { final Exporter.Config config = createConfig("_http", builder.build()); final SettingsException exception = expectThrows(SettingsException.class, () -> { - new HttpExporter(config, environment); + new HttpExporter(config, environment, new SSLService(builder.build(), environment)); }); assertThat(exception.getMessage(), equalTo("[xpack.monitoring.exporters._http.host] invalid host: [" + invalidHost + "]")); @@ -119,7 +120,7 @@ public class HttpExporterSimpleTests extends ESTestCase { final Exporter.Config config = createConfig("_http", builder.build()); - new HttpExporter(config, environment); + new HttpExporter(config, environment, new SSLService(builder.build(), environment)); } /** diff --git a/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/security/MonitoringSettingsFilterTests.java b/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/security/MonitoringSettingsFilterTests.java index fdf55898081..5a65710d22d 100644 --- a/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/security/MonitoringSettingsFilterTests.java +++ b/elasticsearch/x-pack/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/security/MonitoringSettingsFilterTests.java @@ -28,6 +28,7 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; +// TODO: we do not need individual tests for monitoring and security... maybe watcher even has one too? public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase { @Override @@ -40,9 +41,10 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase { .put("xpack.monitoring.exporters._http.enabled", false) .put("xpack.monitoring.exporters._http.auth.username", "_user") .put("xpack.monitoring.exporters._http.auth.password", "_passwd") - .put("xpack.monitoring.exporters._http.ssl.truststore.path", "/path/to/truststore") - .put("xpack.monitoring.exporters._http.ssl.truststore.password", "_passwd") - .put("xpack.monitoring.exporters._http.ssl.hostname_verification", true) + .put("xpack.monitoring.exporters._http.ssl.truststore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) + .put("xpack.monitoring.exporters._http.ssl.truststore.password", "truststore-testnode-only") + .put("xpack.monitoring.exporters._http.ssl.verification_mode", "full") .build(); } @@ -77,7 +79,7 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase { assertNullSetting(settings, "xpack.monitoring.exporters._http.auth.password"); assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.truststore.path"); assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.truststore.password"); - assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.hostname_verification"); + assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.verification_mode"); } } diff --git a/elasticsearch/x-pack/security/bin/x-pack/certgen b/elasticsearch/x-pack/security/bin/x-pack/certgen index 3a148e94351..c0567fd368f 100644 --- a/elasticsearch/x-pack/security/bin/x-pack/certgen +++ b/elasticsearch/x-pack/security/bin/x-pack/certgen @@ -98,7 +98,7 @@ if [ -e "$CONF_DIR" ]; then fi cd "$ES_HOME" > /dev/null -"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.security.ssl.CertificateTool "${args[@]}" +"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.ssl.CertificateTool "${args[@]}" status=$? cd - > /dev/null exit $status diff --git a/elasticsearch/x-pack/security/bin/x-pack/certgen.bat b/elasticsearch/x-pack/security/bin/x-pack/certgen.bat index 7c17d77c330101c23f1a7eb4326015fc2196c11e..c0406b091c9c071fe06c14739f70ab34d0747fd1 100644 GIT binary patch delta 11 Scmcb~bb)DuDdS{2Mri;V2m^rt delta 44 zcmcb>bdza=DWghia%oX!Nu^$KagLsIYEemMT4r)$Noq)bevX2w7FU3OfD0D@Zxat9 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 202913cbef1..88a7e17df60 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 @@ -96,9 +96,6 @@ 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.SSLConfigurationReloader; -import org.elasticsearch.xpack.security.ssl.SSLService; -import org.elasticsearch.xpack.security.support.OptionalSettings; import org.elasticsearch.xpack.security.transport.SecurityServerTransportService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; @@ -106,6 +103,7 @@ import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport; import org.elasticsearch.xpack.security.user.AnonymousUser; +import org.elasticsearch.xpack.ssl.SSLService; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -135,7 +133,8 @@ public class Security implements ActionPlugin, IngestPlugin { public static final String NAME3 = XPackPlugin.SECURITY + "3"; public static final String NAME4 = XPackPlugin.SECURITY + "4"; - public static final Setting> USER_SETTING = OptionalSettings.createString(setting("user"), Property.NodeScope); + public static final Setting> USER_SETTING = + new Setting<>(setting("user"), (String) null, Optional::ofNullable, Property.NodeScope); public static final Setting> AUDIT_OUTPUTS_SETTING = Setting.listSetting(setting("audit.outputs"), @@ -149,8 +148,9 @@ public class Security implements ActionPlugin, IngestPlugin { private final boolean transportClientMode; private final XPackLicenseState licenseState; private final CryptoService cryptoService; + private final SSLService sslService; - public Security(Settings settings, Environment env, XPackLicenseState licenseState) throws IOException { + public Security(Settings settings, Environment env, XPackLicenseState licenseState, SSLService sslService) throws IOException { this.settings = settings; this.env = env; this.transportClientMode = XPackPlugin.transportClientMode(settings); @@ -162,6 +162,7 @@ public class Security implements ActionPlugin, IngestPlugin { cryptoService = null; } this.licenseState = licenseState; + this.sslService = sslService; } public CryptoService getCryptoService() { @@ -180,7 +181,7 @@ public class Security implements ActionPlugin, IngestPlugin { } modules.add(b -> { // for transport client we still must inject these ssl classes with guice - b.bind(SSLService.class).toInstance(new SSLService(settings, null)); + b.bind(SSLService.class).toInstance(sslService); }); return modules; @@ -224,11 +225,6 @@ public class Security implements ActionPlugin, IngestPlugin { final SecurityContext securityContext = new SecurityContext(settings, threadPool, cryptoService); components.add(securityContext); - 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); final ReservedRealm reservedRealm = new ReservedRealm(env, settings, nativeUsersStore); @@ -238,7 +234,7 @@ public class Security implements ActionPlugin, IngestPlugin { realmFactories.put(ActiveDirectoryRealm.TYPE, 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)); + realmFactories.put(PkiRealm.TYPE, config -> new PkiRealm(config, resourceWatcherService, sslService)); for (XPackExtension extension : extensions) { Map newRealms = extension.getRealms(); for (Map.Entry entry : newRealms.entrySet()) { @@ -375,12 +371,6 @@ public class Security implements ActionPlugin, IngestPlugin { // always register for both client and node modes settingsList.add(USER_SETTING); - // SSL settings - SSLService.addSettings(settingsList); - - // transport settings - SecurityNetty3Transport.addSettings(settingsList); - if (transportClientMode) { return settingsList; } @@ -403,9 +393,6 @@ public class Security implements ActionPlugin, IngestPlugin { AuthenticationService.addSettings(settingsList); AuthorizationService.addSettings(settingsList); - // HTTP settings - SecurityNetty3HttpServerTransport.addSettings(settingsList); - // encryption settings CryptoService.addSettings(settingsList); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java index 38681ace843..8c636cc8e00 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java @@ -26,12 +26,13 @@ import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore; import org.elasticsearch.xpack.security.authz.store.RolesStore; import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.xpack.security.user.AnonymousUser; +import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; +import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED; + /** - * + * Indicates whether the features of Security are currently in use */ public class SecurityFeatureSet implements XPackFeatureSet { @@ -114,8 +115,8 @@ public class SecurityFeatureSet implements XPackFeatureSet { static Map sslUsage(Settings settings) { Map map = new HashMap<>(2); - map.put("http", Collections.singletonMap("enabled", SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings))); - map.put("transport", Collections.singletonMap("enabled", SecurityNetty3Transport.SSL_SETTING.get(settings))); + map.put("http", Collections.singletonMap("enabled", HTTP_SSL_ENABLED.get(settings))); + map.put("transport", Collections.singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings))); return map; } 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 06d6415a660..97cfad7c6af 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; /** * 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 3f62fc091be..c06743f7ff4 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import java.util.concurrent.ExecutionException; 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 d34366d8623..0d896971b23 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 @@ -28,7 +28,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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import java.io.BufferedReader; import java.io.IOException; 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 9b2b4b71753..a9fa797a67f 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; /** 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 e3671d55802..9be620c6667 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 @@ -15,7 +15,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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import java.text.MessageFormat; import java.util.Locale; 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 89c9698cb1f..2afc15f923e 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.support.Exceptions; import java.util.Locale; 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 7748fc38048..e3b58d1cebf 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import javax.net.SocketFactory; import java.util.regex.Pattern; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index d4b71faadc3..2b0e4edb58e 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -8,38 +8,39 @@ package org.elasticsearch.xpack.security.authc.pki; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.Security; +import org.elasticsearch.xpack.security.authc.Realms; +import org.elasticsearch.xpack.ssl.CertUtils; +import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.authc.AuthenticationToken; import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.DnRoleMapper; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; -import org.elasticsearch.xpack.security.user.User; -import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import java.io.InputStream; -import java.nio.file.Files; -import java.security.KeyStore; +import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.elasticsearch.xpack.security.Security.setting; +import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; +import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED; + public class PkiRealm extends Realm { public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE"; @@ -49,23 +50,23 @@ public class PkiRealm extends Realm { // For client based cert validation, the auth type must be specified but UNKNOWN is an acceptable value public static final String AUTH_TYPE = "UNKNOWN"; - private final X509TrustManager[] trustManagers; + private final X509TrustManager trustManager; private final Pattern principalPattern; private final DnRoleMapper roleMapper; - public PkiRealm(RealmConfig config, ResourceWatcherService watcherService) { - this(config, new DnRoleMapper(TYPE, config, watcherService, null)); + public PkiRealm(RealmConfig config, ResourceWatcherService watcherService, SSLService sslService) { + this(config, new DnRoleMapper(TYPE, config, watcherService, null), sslService); } // pkg private for testing - PkiRealm(RealmConfig config, DnRoleMapper roleMapper) { + PkiRealm(RealmConfig config, DnRoleMapper roleMapper, SSLService sslService) { super(TYPE, config); - this.trustManagers = trustManagers(config.settings(), config.env()); + this.trustManager = trustManagers(config); this.principalPattern = Pattern.compile(config.settings().get("username_pattern", DEFAULT_USERNAME_PATTERN), Pattern.CASE_INSENSITIVE); this.roleMapper = roleMapper; - checkSSLEnabled(config, logger); + checkSSLEnabled(config, sslService); } @Override @@ -81,7 +82,7 @@ public class PkiRealm extends Realm { @Override public User authenticate(AuthenticationToken authToken) { X509AuthenticationToken token = (X509AuthenticationToken)authToken; - if (!isCertificateChainTrusted(trustManagers, token, logger)) { + if (isCertificateChainTrusted(trustManager, token, logger) == false) { return null; } @@ -129,94 +130,95 @@ public class PkiRealm extends Realm { return new X509AuthenticationToken(certificates, principal, dn); } - static boolean isCertificateChainTrusted(X509TrustManager[] trustManagers, X509AuthenticationToken token, Logger logger) { - if (trustManagers.length > 0) { - boolean trusted = false; - for (X509TrustManager trustManager : trustManagers) { - try { - trustManager.checkClientTrusted(token.credentials(), AUTH_TYPE); - trusted = true; - break; - } catch (CertificateException e) { - if (logger.isTraceEnabled()) { - logger.trace( - (Supplier) () -> new ParameterizedMessage( - "failed certificate validation for principal [{}]", token.principal()), e); - } else if (logger.isDebugEnabled()) { - logger.debug("failed certificate validation for principal [{}]", token.principal()); - } + static boolean isCertificateChainTrusted(X509TrustManager trustManager, X509AuthenticationToken token, Logger logger) { + if (trustManager != null) { + try { + trustManager.checkClientTrusted(token.credentials(), AUTH_TYPE); + return true; + } catch (CertificateException e) { + if (logger.isTraceEnabled()) { + logger.trace((Supplier) + () -> new ParameterizedMessage("failed certificate validation for principal [{}]", token.principal()), e); + } else if (logger.isDebugEnabled()) { + logger.debug("failed certificate validation for principal [{}]", token.principal()); } } - - return trusted; + return false; } // No extra trust managers specified, so at this point we can be considered authenticated. return true; } - static X509TrustManager[] trustManagers(Settings settings, Environment env) { + static X509TrustManager trustManagers(RealmConfig realmConfig) { + final Settings settings = realmConfig.settings(); + final Environment env = realmConfig.env(); + String[] certificateAuthorities = settings.getAsArray("certificate_authorities", null); String truststorePath = settings.get("truststore.path"); - if (truststorePath == null) { - return new X509TrustManager[0]; + if (truststorePath == null && certificateAuthorities == null) { + return null; + } else if (truststorePath != null && certificateAuthorities != null) { + final String settingPrefix = Realms.REALMS_GROUPS_SETTINGS.getKey() + realmConfig.name() + "."; + throw new IllegalArgumentException("[" + settingPrefix + "truststore.path] and [" + settingPrefix + "certificate_authorities]" + + " cannot be used at the same time"); + } else if (truststorePath != null) { + return trustManagersFromTruststore(realmConfig); } + return trustManagersFromCAs(settings, env); + } + private static X509TrustManager trustManagersFromTruststore(RealmConfig realmConfig) { + final Settings settings = realmConfig.settings(); + String truststorePath = settings.get("truststore.path"); String password = settings.get("truststore.password"); if (password == null) { - throw new IllegalArgumentException("no truststore password configured"); + final String settingPrefix = Realms.REALMS_GROUPS_SETTINGS.getKey() + realmConfig.name() + "."; + throw new IllegalArgumentException("[" + settingPrefix + "truststore.password] is not configured"); } String trustStoreAlgorithm = settings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); - TrustManager[] trustManagers; - try (InputStream in = Files.newInputStream(XPackPlugin.resolveConfigFile(env, truststorePath))) { - // Load TrustStore - KeyStore ks = KeyStore.getInstance("jks"); - ks.load(in, password.toCharArray()); - - // Initialize a trust manager factory with the trusted store - TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm); - trustFactory.init(ks); - trustManagers = trustFactory.getTrustManagers(); + try { + return CertUtils.trustManager(truststorePath, password, trustStoreAlgorithm, realmConfig.env()); } catch (Exception e) { throw new IllegalArgumentException("failed to load specified truststore", e); } + } - List trustManagerList = new ArrayList<>(); - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509TrustManager) { - trustManagerList.add((X509TrustManager) trustManager); - } + private static X509TrustManager trustManagersFromCAs(Settings settings, Environment env) { + String[] certificateAuthorities = settings.getAsArray("certificate_authorities", null); + assert certificateAuthorities != null; + try { + Certificate[] certificates = CertUtils.readCertificates(Arrays.asList(certificateAuthorities), env); + return CertUtils.trustManager(certificates); + } catch (Exception e) { + throw new ElasticsearchException("failed to load certificate authorities for PKI realm", e); } - - if (trustManagerList.isEmpty()) { - throw new IllegalArgumentException("no valid certificates found in truststore"); - } - - return trustManagerList.toArray(new X509TrustManager[trustManagerList.size()]); } /** * Checks to see if both SSL and Client authentication are enabled on at least one network communication layer. If - * not an error message will be logged + * not an exception will be thrown * * @param config this realm's configuration - * @param logger the logger to use if there is a configuration issue + * @param sslService the SSLService to use for ssl configurations */ - static void checkSSLEnabled(RealmConfig config, Logger logger) { + static void checkSSLEnabled(RealmConfig config, SSLService sslService) { Settings settings = config.globalSettings(); - final boolean httpSsl = SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings); - final boolean httpClientAuth = SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.get(settings).enabled(); // HTTP + final boolean httpSsl = HTTP_SSL_ENABLED.get(settings); + Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings); + final boolean httpClientAuth = sslService.isSSLClientAuthEnabled(httpSSLSettings); if (httpSsl && httpClientAuth) { return; } // Default Transport - final boolean ssl = SecurityNetty3Transport.SSL_SETTING.get(settings); - final SSLClientAuth clientAuth = SecurityNetty3Transport.CLIENT_AUTH_SETTING.get(settings); - if (ssl && clientAuth.enabled()) { + final boolean ssl = TRANSPORT_SSL_ENABLED.get(settings); + final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); + final boolean clientAuthEnabled = sslService.isSSLClientAuthEnabled(transportSSLSettings); + if (ssl && clientAuthEnabled) { return; } @@ -224,13 +226,14 @@ public class PkiRealm extends Realm { Map groupedSettings = settings.getGroups("transport.profiles."); for (Map.Entry entry : groupedSettings.entrySet()) { Settings profileSettings = entry.getValue().getByPrefix(Security.settingPrefix()); - if (SecurityNetty3Transport.profileSsl(profileSettings, settings) - && SecurityNetty3Transport.CLIENT_AUTH_SETTING.get(profileSettings, settings).enabled()) { + if (SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings) + && sslService.isSSLClientAuthEnabled( + SecurityNetty3Transport.profileSslSettings(profileSettings), transportSSLSettings)) { return; } } - logger.error("PKI realm [{}] is enabled but cannot be used as neither HTTP or Transport have both SSL and client authentication " + - "enabled", config.name()); + throw new IllegalStateException("PKI realm [" + config.name() + "] is enabled but cannot be used as neither HTTP or Transport " + + "has SSL with client authentication enabled"); } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java index 645ec7b8648..fcc239a070b 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/rest/SecurityRestFilter.java @@ -24,7 +24,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.xpack.security.authc.pki.PkiRealm; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; +import org.elasticsearch.xpack.ssl.SSLService; import org.jboss.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; @@ -32,6 +32,8 @@ import javax.net.ssl.SSLPeerUnverifiedException; import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; + /** * */ @@ -45,14 +47,15 @@ public class SecurityRestFilter extends RestFilter { @Inject public SecurityRestFilter(AuthenticationService service, RestController controller, Settings settings, - ThreadPool threadPool, XPackLicenseState licenseState) { + ThreadPool threadPool, XPackLicenseState licenseState, SSLService sslService) { this.service = service; this.licenseState = licenseState; this.threadContext = threadPool.getThreadContext(); + this.logger = Loggers.getLogger(getClass(), settings); + final boolean ssl = HTTP_SSL_ENABLED.get(settings); + Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings); + this.extractClientCertificate = ssl && sslService.isSSLClientAuthEnabled(httpSSLSettings); controller.registerFilter(this); - boolean ssl = SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings); - extractClientCertificate = ssl && SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.get(settings).enabled(); - logger = Loggers.getLogger(getClass(), settings); } @Override 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 deleted file mode 100644 index 71ae083862b..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfiguration.java +++ /dev/null @@ -1,447 +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 javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManagerFactory; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; - -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Setting.Property; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.env.Environment; - -import static org.elasticsearch.xpack.security.Security.setting; -import static org.elasticsearch.xpack.security.support.OptionalSettings.createInt; -import static org.elasticsearch.xpack.security.support.OptionalSettings.createString; -import static org.elasticsearch.xpack.security.support.OptionalSettings.createTimeValue; - -/** - * Class that contains all configuration related to SSL use within x-pack - */ -abstract class SSLConfiguration { - - abstract KeyConfig keyConfig(); - - abstract TrustConfig trustConfig(); - - abstract String protocol(); - - abstract int sessionCacheSize(); - - abstract TimeValue sessionCacheTimeout(); - - abstract List ciphers(); - - abstract List supportedProtocols(); - - /** - * Provides the list of paths to files that back this configuration - */ - List filesToMonitor(@Nullable Environment environment) { - if (keyConfig() == trustConfig()) { - return keyConfig().filesToMonitor(environment); - } - List paths = new ArrayList<>(keyConfig().filesToMonitor(environment)); - paths.addAll(trustConfig().filesToMonitor(environment)); - return paths; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SSLConfiguration)) return false; - - SSLConfiguration that = (SSLConfiguration) o; - - if (this.sessionCacheSize() != that.sessionCacheSize()) { - return false; - } - if (this.keyConfig() != null ? !this.keyConfig().equals(that.keyConfig()) : that.keyConfig() != null) { - return false; - } - if (this.trustConfig() != null ? !this.trustConfig().equals(that.trustConfig()) : that.trustConfig() != null) { - return false; - } - if (this.protocol() != null ? !this.protocol().equals(that.protocol()) : that.protocol() != null) { - return false; - } - if (this.sessionCacheTimeout() != null ? - !this.sessionCacheTimeout().equals(that.sessionCacheTimeout()) : that.sessionCacheTimeout() != null) { - return false; - } - if (this.ciphers() != null ? !this.ciphers().equals(that.ciphers()) : that.ciphers() != null) { - return false; - } - return this.supportedProtocols() != null ? - this.supportedProtocols().equals(that.supportedProtocols()) : that.supportedProtocols() == null; - } - - @Override - public int hashCode() { - int result = this.keyConfig() != null ? this.keyConfig().hashCode() : 0; - result = 31 * result + (this.trustConfig() != null ? this.trustConfig().hashCode() : 0); - result = 31 * result + (this.protocol() != null ? this.protocol().hashCode() : 0); - result = 31 * result + this.sessionCacheSize(); - result = 31 * result + (this.sessionCacheTimeout() != null ? this.sessionCacheTimeout().hashCode() : 0); - result = 31 * result + (this.ciphers() != null ? this.ciphers().hashCode() : 0); - result = 31 * result + (this.supportedProtocols() != null ? this.supportedProtocols().hashCode() : 0); - return result; - } - - static class Global extends SSLConfiguration { - - 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"); - 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, - Function.identity(), Property.NodeScope, Property.Filtered); - static final Setting> SUPPORTED_PROTOCOLS_SETTING = Setting.listSetting(globalKey(Custom.SUPPORTED_PROTOCOLS_SETTING), - DEFAULT_SUPPORTED_PROTOCOLS, Function.identity(), Property.NodeScope, Property.Filtered); - static final Setting PROTOCOL_SETTING = new Setting<>(globalKey(Custom.PROTOCOL_SETTING), DEFAULT_PROTOCOL, - Function.identity(), Property.NodeScope, Property.Filtered); - static final Setting SESSION_CACHE_SIZE_SETTING = Setting.intSetting(globalKey(Custom.CACHE_SIZE_SETTING), - 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); - - // keystore settings - static final Setting> KEYSTORE_PATH_SETTING = createString(globalKey(Custom.KEYSTORE_PATH_SETTING), - s -> System.getProperty("javax.net.ssl.keyStore"), Property.NodeScope, Property.Filtered); - static final Setting> KEYSTORE_PASSWORD_SETTING = createString(globalKey(Custom.KEYSTORE_PASSWORD_SETTING), - s -> System.getProperty("javax.net.ssl.keyStorePassword"), Property.NodeScope, Property.Filtered); - static final Setting KEYSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.KEYSTORE_ALGORITHM_SETTING), - s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), - Function.identity(), Property.NodeScope, Property.Filtered); - static final Setting> KEYSTORE_KEY_PASSWORD_SETTING = - createString(globalKey(Custom.KEYSTORE_KEY_PASSWORD_SETTING), KEYSTORE_PASSWORD_SETTING, - Property.NodeScope, Property.Filtered); - - // truststore settings - static final Setting> TRUSTSTORE_PATH_SETTING = createString(globalKey(Custom.TRUSTSTORE_PATH_SETTING), - s -> System.getProperty("javax.net.ssl.trustStore"), Property.NodeScope, Property.Filtered); - static final Setting> TRUSTSTORE_PASSWORD_SETTING = createString(globalKey(Custom.TRUSTSTORE_PASSWORD_SETTING), - s -> System.getProperty("javax.net.ssl.trustStorePassword"), Property.NodeScope, Property.Filtered); - static final Setting TRUSTSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.TRUSTSTORE_ALGORITHM_SETTING), - s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()), - Function.identity(), Property.NodeScope, Property.Filtered); - - // PEM key and cert settings - static final Setting> KEY_PATH_SETTING = createString(globalKey(Custom.KEY_PATH_SETTING), - Property.NodeScope, Property.Filtered); - static final Setting> KEY_PASSWORD_SETTING = createString(globalKey(Custom.KEY_PASSWORD_SETTING), - Property.NodeScope, Property.Filtered); - static final Setting> CERT_SETTING = Setting.listSetting(globalKey(Custom.CERT_SETTING), Collections.emptyList(), - s -> s, Property.NodeScope, Property.Filtered); - - // PEM trusted certs - static final Setting> CA_PATHS_SETTING = Setting.listSetting(globalKey(Custom.CA_PATHS_SETTING), - Collections.emptyList(), s -> s, Property.NodeScope, Property.Filtered); - - // Default system trusted certs - static final Setting INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting(globalKey(Custom.INCLUDE_JDK_CERTS_SETTING), true, - Property.NodeScope, Property.Filtered); - - private final KeyConfig keyConfig; - private final TrustConfig trustConfig; - private final String sslProtocol; - private final int sessionCacheSize; - private final TimeValue sessionCacheTimeout; - private final List ciphers; - private final List supportedProtocols; - - /** - * This constructor should be used with the global settings of the service - * - * @param settings the global settings to build the SSL configuration from - */ - Global(Settings settings) { - this.keyConfig = createGlobalKeyConfig(settings); - this.trustConfig = createGlobalTrustConfig(settings, keyConfig); - this.sslProtocol = PROTOCOL_SETTING.get(settings); - this.sessionCacheSize = SESSION_CACHE_SIZE_SETTING.get(settings); - this.sessionCacheTimeout = SESSION_CACHE_TIMEOUT_SETTING.get(settings); - this.ciphers = CIPHERS_SETTING.get(settings); - this.supportedProtocols = SUPPORTED_PROTOCOLS_SETTING.get(settings); - } - - @Override - KeyConfig keyConfig() { - return keyConfig; - } - - @Override - TrustConfig trustConfig() { - return trustConfig; - } - - @Override - String protocol() { - return sslProtocol; - } - - @Override - int sessionCacheSize() { - return sessionCacheSize; - } - - @Override - TimeValue sessionCacheTimeout() { - return sessionCacheTimeout; - } - - @Override - List ciphers() { - return ciphers; - } - - @Override - List supportedProtocols() { - return supportedProtocols; - } - - @Override - public String toString() { - return "SSLConfiguration{" + - "keyConfig=[" + keyConfig + - "], trustConfig=" + trustConfig + - "], sslProtocol=['" + sslProtocol + '\'' + - "], sessionCacheSize=[" + sessionCacheSize + - "], sessionCacheTimeout=[" + sessionCacheTimeout + - "], ciphers=[" + ciphers + - "], supportedProtocols=[" + supportedProtocols + - "]}"; - } - - private static String globalKey(Setting setting) { - return setting("ssl." + setting.getKey()); - } - - static KeyConfig createGlobalKeyConfig(Settings settings) { - String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null); - String keyPath = KEY_PATH_SETTING.get(settings).orElse(null); - if (keyPath != null && keyStorePath != null) { - throw new IllegalArgumentException("you cannot specify a keystore and key file"); - } else if (keyStorePath == null && keyPath == null) { - return KeyConfig.NONE; - } - - boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings); - if (keyPath != null) { - String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null); - List certPaths = getListOrNull(CERT_SETTING, settings); - if (certPaths == null) { - throw new IllegalArgumentException("you must specify the certificates to use with the key"); - } - return new PEMKeyConfig(includeSystem, keyPath, keyPassword, certPaths); - } else { - assert keyStorePath != null; - String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null); - String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings); - String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword); - String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); - return new StoreKeyConfig(includeSystem, keyStorePath, keyStorePassword, keyStoreKeyPassword, - keyStoreAlgorithm, trustStoreAlgorithm); - } - } - - static TrustConfig createGlobalTrustConfig(Settings settings, KeyConfig keyInfo) { - String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null); - List caPaths = getListOrNull(CA_PATHS_SETTING, settings); - boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings); - if (trustStorePath != null && caPaths != null) { - throw new IllegalArgumentException("you cannot specify a truststore and ca files"); - } else if (caPaths != null) { - return new PEMTrustConfig(includeSystem, caPaths); - } else if (trustStorePath != null) { - String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null); - String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); - return new StoreTrustConfig(includeSystem, trustStorePath, trustStorePassword, trustStoreAlgorithm); - } else if (keyInfo != KeyConfig.NONE) { - return keyInfo; - } else { - return new StoreTrustConfig(includeSystem, null, null, null); - } - } - } - - static class Custom extends SSLConfiguration { - - static final Setting> PROTOCOL_SETTING = createString("protocol"); - static final Setting> CACHE_SIZE_SETTING = createInt("session.cache_size"); - static final Setting> CACHE_TIMEOUT_SETTING = createTimeValue("session.cache_timeout"); - static final Setting> CIPHERS_SETTING = Setting.listSetting("ciphers", Collections.emptyList(), s -> s); - static final Setting> SUPPORTED_PROTOCOLS_SETTING = - Setting.listSetting("supported_protocols", Collections.emptyList(), s -> s); - - static final Setting> KEYSTORE_PATH_SETTING = createString("keystore.path"); - static final Setting> KEYSTORE_PASSWORD_SETTING = createString("keystore.password"); - static final Setting KEYSTORE_ALGORITHM_SETTING = new Setting<>("keystore.algorithm", - s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), Function.identity()); - static final Setting> KEYSTORE_KEY_PASSWORD_FALLBACK = createString("keystore.password"); - static final Setting> KEYSTORE_KEY_PASSWORD_SETTING = - createString("keystore.key_password", KEYSTORE_KEY_PASSWORD_FALLBACK); - - - static final Setting> TRUSTSTORE_PATH_SETTING = createString("truststore.path"); - static final Setting> TRUSTSTORE_PASSWORD_SETTING = createString("truststore.password"); - static final Setting TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("truststore.algorithm", - s -> System.getProperty("ssl.TrustManagerFactory.algorithm", - TrustManagerFactory.getDefaultAlgorithm()), Function.identity()); - - static final Setting> KEY_PATH_SETTING = createString("key.path"); - static final Setting> KEY_PASSWORD_SETTING = createString("key.password"); - static final Setting> CERT_SETTING = Setting.listSetting("cert", Collections.emptyList(), s -> s); - - 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); - - private final KeyConfig keyConfig; - private final TrustConfig trustConfig; - private final String sslProtocol; - private final int sessionCacheSize; - private final TimeValue sessionCacheTimeout; - private final List ciphers; - private final List supportedProtocols; - - /** - * The settings passed in should be the group settings under ssl, like xpack.security.ssl - * - * @param settings the profile settings to get the SSL configuration for - * @param defaultConfig the default SSL configuration - */ - Custom(Settings settings, SSLConfiguration defaultConfig) { - Objects.requireNonNull(settings); - this.keyConfig = createKeyConfig(settings, defaultConfig); - this.trustConfig = createTrustConfig(settings, keyConfig, defaultConfig); - this.sslProtocol = PROTOCOL_SETTING.get(settings).orElse(defaultConfig.protocol()); - this.sessionCacheSize = CACHE_SIZE_SETTING.get(settings).orElse(defaultConfig.sessionCacheSize()); - this.sessionCacheTimeout = CACHE_TIMEOUT_SETTING.get(settings).orElse(defaultConfig.sessionCacheTimeout()); - this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, defaultConfig.ciphers()); - this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, defaultConfig.supportedProtocols()); - } - - @Override - KeyConfig keyConfig() { - return keyConfig; - } - - @Override - TrustConfig trustConfig() { - return trustConfig; - } - - @Override - String protocol() { - return sslProtocol; - } - - @Override - int sessionCacheSize() { - return sessionCacheSize; - } - - @Override - TimeValue sessionCacheTimeout() { - return sessionCacheTimeout; - } - - @Override - List ciphers() { - return ciphers; - } - - @Override - List supportedProtocols() { - return supportedProtocols; - } - - @Override - public String toString() { - return "SSLConfiguration{" + - "keyConfig=[" + keyConfig + - "], trustConfig=" + trustConfig + - "], sslProtocol=['" + sslProtocol + '\'' + - "], sessionCacheSize=[" + sessionCacheSize + - "], sessionCacheTimeout=[" + sessionCacheTimeout + - "], ciphers=[" + ciphers + - "], supportedProtocols=[" + supportedProtocols + - '}'; - } - - static KeyConfig createKeyConfig(Settings settings, SSLConfiguration global) { - String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null); - String keyPath = KEY_PATH_SETTING.get(settings).orElse(null); - if (keyPath != null && keyStorePath != null) { - throw new IllegalArgumentException("you cannot specify a keystore and key file"); - } else if (keyStorePath == null && keyPath == null) { - return global.keyConfig(); - } - - boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings); - if (keyPath != null) { - String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null); - List certPaths = getListOrNull(CERT_SETTING, settings); - if (certPaths == null) { - throw new IllegalArgumentException("you must specify the certificates to use with the key"); - } - return new PEMKeyConfig(includeSystem, keyPath, keyPassword, certPaths); - } else { - assert keyStorePath != null; - String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null); - String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings); - String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword); - String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); - return new StoreKeyConfig(includeSystem, keyStorePath, keyStorePassword, keyStoreKeyPassword, - keyStoreAlgorithm, trustStoreAlgorithm); - } - } - - static TrustConfig createTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) { - String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null); - List caPaths = getListOrNull(CA_PATHS_SETTING, settings); - if (trustStorePath != null && caPaths != null) { - throw new IllegalArgumentException("you cannot specify a truststore and ca files"); - } else if (caPaths != null) { - return new PEMTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings), caPaths); - } else if (trustStorePath != null) { - String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null); - String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); - return new StoreTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings), - trustStorePath, trustStorePassword, trustStoreAlgorithm); - } else if (keyConfig == global.keyConfig()) { - return global.trustConfig(); - } else { - return keyConfig; - } - } - } - - static List getListOrNull(Setting> listSetting, Settings settings) { - return getListOrDefault(listSetting, settings, null); - } - - static List getListOrDefault(Setting> listSetting, Settings settings, List defaultValue) { - if (listSetting.exists(settings)) { - return listSetting.get(settings); - } - return defaultValue; - } -} 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 deleted file mode 100644 index b6196073ed5..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/TrustConfig.java +++ /dev/null @@ -1,156 +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.Nullable; -import org.elasticsearch.env.Environment; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509ExtendedTrustManager; -import java.net.Socket; -import java.nio.file.Path; -import java.security.KeyStore; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.List; - -abstract class TrustConfig { - - protected final boolean includeSystem; - - TrustConfig(boolean includeSystem) { - this.includeSystem = includeSystem; - } - - 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); - - abstract void validate(); - - abstract List filesToMonitor(@Nullable Environment environment); - - public abstract String toString(); - - private X509ExtendedTrustManager mergeWithSystem(X509ExtendedTrustManager nonSystemTrustManager) { - try { - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init((KeyStore) null); - TrustManager[] systemTrustManagers = tmf.getTrustManagers(); - X509ExtendedTrustManager system = findFirstX509ExtendedTrustManager(systemTrustManagers); - if (nonSystemTrustManager == null) { - return system; - } - - return new CombiningX509TrustManager(nonSystemTrustManager, system); - } catch (Exception e) { - throw new ElasticsearchException("failed to initialize a trust managers", e); - } - } - - private static X509ExtendedTrustManager findFirstX509ExtendedTrustManager(TrustManager[] trustManagers) { - X509ExtendedTrustManager x509TrustManager = null; - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509ExtendedTrustManager) { - // first one wins like in the JDK - x509TrustManager = (X509ExtendedTrustManager) trustManager; - break; - } - } - if (x509TrustManager == null) { - throw new IllegalArgumentException("did not find a X509ExtendedTrustManager"); - } - return x509TrustManager; - } - - private static class CombiningX509TrustManager extends X509ExtendedTrustManager { - - private final X509ExtendedTrustManager first; - private final X509ExtendedTrustManager second; - - private final X509Certificate[] acceptedIssuers; - - CombiningX509TrustManager(X509ExtendedTrustManager first, X509ExtendedTrustManager second) { - this.first = first; - this.second = second; - X509Certificate[] firstIssuers = first.getAcceptedIssuers(); - X509Certificate[] secondIssuers = second.getAcceptedIssuers(); - this.acceptedIssuers = new X509Certificate[firstIssuers.length + secondIssuers.length]; - System.arraycopy(firstIssuers, 0, acceptedIssuers, 0, firstIssuers.length); - System.arraycopy(secondIssuers, 0, acceptedIssuers, firstIssuers.length, secondIssuers.length); - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { - try { - first.checkClientTrusted(x509Certificates, s, socket); - } catch (CertificateException e) { - second.checkClientTrusted(x509Certificates, s, socket); - } - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException { - try { - first.checkServerTrusted(x509Certificates, s, socket); - } catch (CertificateException e) { - second.checkServerTrusted(x509Certificates, s, socket); - } - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { - try { - first.checkClientTrusted(x509Certificates, s, sslEngine); - } catch (CertificateException e) { - second.checkClientTrusted(x509Certificates, s, sslEngine); - } - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException { - try { - first.checkServerTrusted(x509Certificates, s, sslEngine); - } catch (CertificateException e) { - second.checkServerTrusted(x509Certificates, s, sslEngine); - } - } - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - try { - first.checkClientTrusted(x509Certificates, s); - } catch (CertificateException e) { - second.checkClientTrusted(x509Certificates, s); - } - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - try { - first.checkServerTrusted(x509Certificates, s); - } catch (CertificateException e) { - second.checkServerTrusted(x509Certificates, s); - } - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return acceptedIssuers; - } - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/support/OptionalSettings.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/support/OptionalSettings.java deleted file mode 100644 index 58c0fcf50aa..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/support/OptionalSettings.java +++ /dev/null @@ -1,51 +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.support; - -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Setting.Property; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; - -import java.util.Optional; -import java.util.function.Function; - -public class OptionalSettings { - - private OptionalSettings() {} - - public static Setting> createInt(String key, Property... properties) { - return new Setting<>(key, s -> null, s -> { - if (s != null) { - return Optional.of(Integer.parseInt(s)); - } else { - return Optional.ofNullable(null); - } - }, properties); - } - - public static Setting> createString(String key, Property... properties) { - return createString(key, s -> null, properties); - } - - public static Setting> createString(String key, Function defaultValue, Property... properties) { - return new Setting<>(key, defaultValue, Optional::ofNullable, properties); - } - - public static Setting> createString(String key, Setting> fallback, Property... properties) { - return new Setting<>(key, fallback, Optional::ofNullable, properties); - } - - public static Setting> createTimeValue(String key, Property... properties) { - return new Setting<>(key, s-> null, s -> { - if (s != null) { - return Optional.of(TimeValue.parseTimeValue(s, key)); - } else { - return Optional.ofNullable(null); - } - }, properties); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportService.java index 2090ae6b246..defb17dc598 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportService.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportService.java @@ -15,6 +15,7 @@ import org.elasticsearch.xpack.security.authz.AuthorizationService; import org.elasticsearch.xpack.security.authz.AuthorizationUtils; import org.elasticsearch.xpack.security.authz.accesscontrol.RequestContext; import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; @@ -36,32 +37,33 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; -import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.CLIENT_AUTH_SETTING; -import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING; -import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.SSL_SETTING; +import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED; +import static org.elasticsearch.xpack.security.Security.setting; public class SecurityServerTransportService extends TransportService { - public static final String SETTING_NAME = "xpack.security.type"; + private static final String SETTING_NAME = "xpack.security.type"; - protected final AuthenticationService authcService; - protected final AuthorizationService authzService; - protected final SecurityActionMapper actionMapper; - protected final XPackLicenseState licenseState; - - protected final Map profileFilters; + private final AuthenticationService authcService; + private final AuthorizationService authzService; + private final SecurityActionMapper actionMapper; + private final SSLService sslService; + private final Map profileFilters; + final XPackLicenseState licenseState; @Inject public SecurityServerTransportService(Settings settings, Transport transport, ThreadPool threadPool, AuthenticationService authcService, AuthorizationService authzService, SecurityActionMapper actionMapper, - XPackLicenseState licenseState) { + XPackLicenseState licenseState, + SSLService sslService) { super(settings, transport, threadPool); this.authcService = authcService; this.authzService = authzService; this.actionMapper = actionMapper; this.licenseState = licenseState; + this.sslService = sslService; this.profileFilters = initializeProfileFilters(); } @@ -119,10 +121,12 @@ public class SecurityServerTransportService extends TransportService { Map profileSettingsMap = settings.getGroups("transport.profiles.", true); Map profileFilters = new HashMap<>(profileSettingsMap.size() + 1); + final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); for (Map.Entry entry : profileSettingsMap.entrySet()) { Settings profileSettings = entry.getValue(); - final boolean profileSsl = SecurityNetty3Transport.profileSsl(profileSettings, settings); - final boolean clientAuth = PROFILE_CLIENT_AUTH_SETTING.get(profileSettings, settings).enabled(); + final boolean profileSsl = SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings); + final Settings profileSslSettings = SecurityNetty3Transport.profileSslSettings(profileSettings); + final boolean clientAuth = sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings); final boolean extractClientCert = profileSsl && clientAuth; String type = entry.getValue().get(SETTING_NAME, "node"); switch (type) { @@ -137,8 +141,8 @@ public class SecurityServerTransportService extends TransportService { } if (!profileFilters.containsKey(TransportSettings.DEFAULT_PROFILE)) { - final boolean profileSsl = SSL_SETTING.get(settings); - final boolean clientAuth = CLIENT_AUTH_SETTING.get(settings).enabled(); + final boolean profileSsl = TRANSPORT_SSL_ENABLED.get(settings); + final boolean clientAuth = sslService.isSSLClientAuthEnabled(transportSSLSettings); final boolean extractClientCert = profileSsl && clientAuth; profileFilters.put(TransportSettings.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), extractClientCert)); @@ -159,9 +163,9 @@ public class SecurityServerTransportService extends TransportService { private final XPackLicenseState licenseState; private final ThreadContext threadContext; - public ProfileSecuredRequestHandler(String action, TransportRequestHandler handler, - Map profileFilters, XPackLicenseState licenseState, - ThreadContext threadContext) { + private ProfileSecuredRequestHandler(String action, TransportRequestHandler handler, + Map profileFilters, XPackLicenseState licenseState, + ThreadContext threadContext) { this.action = action; this.handler = handler; this.profileFilters = profileFilters; 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 3f1d6cfcf41..c59f6a35b73 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 @@ -9,14 +9,11 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.Setting; -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.ssl.SSLService; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.xpack.security.ssl.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; @@ -25,45 +22,28 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; -import java.util.List; import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION; -import static org.elasticsearch.xpack.security.Security.setting; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException; +import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; /** * */ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport { - public static final boolean SSL_DEFAULT = false; - public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.NO.name(); - - public static final Setting DEPRECATED_SSL_SETTING = - Setting.boolSetting(setting("http.ssl"), SSL_DEFAULT, Property.NodeScope, Property.Deprecated); - public static final Setting SSL_SETTING = - Setting.boolSetting(setting("http.ssl.enabled"), DEPRECATED_SSL_SETTING, Property.NodeScope); - public static final Setting CLIENT_AUTH_SETTING = - new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope); - private final IPFilter ipFilter; private final SSLService sslService; private final boolean ssl; - private final Settings sslSettings; @Inject public SecurityNetty3HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter, SSLService sslService, ThreadPool threadPool) { super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; - this.ssl = SSL_SETTING.get(settings); this.sslService = sslService; - if (ssl) { - sslSettings = settings.getByPrefix(setting("http.ssl.")); - } else { - sslSettings = Settings.EMPTY; - } + this.ssl = HTTP_SSL_ENABLED.get(settings); } @Override @@ -109,13 +89,14 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport private class HttpSslChannelPipelineFactory extends HttpChannelPipelineFactory { - private final SSLClientAuth clientAuth; + private final Settings sslSettings; 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"); + this.sslSettings = SSLService.getHttpTransportSSLSettings(settings); + if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting"); } } @@ -123,10 +104,7 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = super.getPipeline(); if (ssl) { - SSLEngine engine = sslService.createSSLEngine(sslSettings); - engine.setUseClientMode(false); - clientAuth.configure(engine); - + SSLEngine engine = sslService.createSSLEngine(sslSettings, Settings.EMPTY); pipeline.addFirst("ssl", new SslHandler(engine)); } pipeline.addFirst("ipfilter", new IPFilterNetty3UpstreamHandler(ipFilter, IPFilter.HTTP_PROFILE_NAME)); @@ -134,14 +112,8 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport } } - public static void addSettings(List> settings) { - settings.add(SSL_SETTING); - settings.add(CLIENT_AUTH_SETTING); - settings.add(DEPRECATED_SSL_SETTING); - } - public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) { - if (SSL_SETTING.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) { + if (HTTP_SSL_ENABLED.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) { settingsBuilder.put(SETTING_HTTP_COMPRESSION.getKey(), false); } } 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 190fea2af8d..ca3d2257be8 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 @@ -7,20 +7,18 @@ package org.elasticsearch.xpack.security.transport.netty3; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; -import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.settings.Setting; -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.transport.TransportSettings; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.netty3.Netty3Transport; -import org.elasticsearch.xpack.security.ssl.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; @@ -31,69 +29,21 @@ import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; import java.io.IOException; import java.net.InetSocketAddress; -import java.util.List; import static org.elasticsearch.xpack.security.Security.setting; -import static org.elasticsearch.xpack.security.Security.settingPrefix; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException; +import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED; public class SecurityNetty3Transport extends Netty3Transport { - public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name(); - public static final boolean SSL_DEFAULT = false; - - public static final Setting DEPRECATED_HOSTNAME_VERIFICATION_SETTING = - Setting.boolSetting( - setting("ssl.hostname_verification"), - true, - new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared}); - - public static final Setting HOSTNAME_VERIFICATION_SETTING = - Setting.boolSetting(setting("ssl.hostname_verification.enabled"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING, - Property.NodeScope, Property.Filtered, Property.Shared); - - public static final Setting HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING = - Setting.boolSetting( - setting("ssl.hostname_verification.resolve_name"), - true, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - - public static final Setting DEPRECATED_SSL_SETTING = - Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT, - Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared); - - public static final Setting SSL_SETTING = - Setting.boolSetting( - setting("transport.ssl.enabled"), - DEPRECATED_SSL_SETTING, - new Property[]{Property.Filtered, Property.NodeScope, Property.Shared}); - - public static final Setting CLIENT_AUTH_SETTING = - new Setting<>( - setting("transport.ssl.client.auth"), - CLIENT_AUTH_DEFAULT, - SSLClientAuth::parse, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - - public static final Setting DEPRECATED_PROFILE_SSL_SETTING = - Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared); - - public static final Setting PROFILE_SSL_SETTING = - Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared); - - public static final Setting PROFILE_CLIENT_AUTH_SETTING = - new Setting<>( - setting("ssl.client.auth"), - CLIENT_AUTH_SETTING, - SSLClientAuth::parse, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); + public static final Setting PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false); private final SSLService sslService; @Nullable private final IPFilter authenticator; + private final Settings transportSSLSettings; private final boolean ssl; @Inject @@ -102,8 +52,10 @@ public class SecurityNetty3Transport extends Netty3Transport { CircuitBreakerService circuitBreakerService) { super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService); this.authenticator = authenticator; - this.ssl = SSL_SETTING.get(settings); + this.ssl = TRANSPORT_SSL_ENABLED.get(settings); this.sslService = sslService; + this.transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); + } @Override @@ -147,42 +99,36 @@ public class SecurityNetty3Transport extends Netty3Transport { } } - public static boolean profileSsl(Settings profileSettings, Settings settings) { - // we can't use the fallback mechanism here since it may not exist in the profile settings and we get the wrong value - // for the profile if they use the old setting - if (PROFILE_SSL_SETTING.exists(profileSettings)) { - return PROFILE_SSL_SETTING.get(profileSettings); - } else if (DEPRECATED_PROFILE_SSL_SETTING.exists(profileSettings)) { - return DEPRECATED_PROFILE_SSL_SETTING.get(profileSettings); - } else { - return SSL_SETTING.get(settings); - } + public static Settings profileSslSettings(Settings profileSettings) { + return profileSettings.getByPrefix(setting("ssl.")); } private class SslServerChannelPipelineFactory extends ServerChannelPipelineFactory { - private final boolean sslEnabled; - private final Settings securityProfileSettings; - private final SSLClientAuth sslClientAuth; + private final boolean profileSsl; + private final Settings profileSslSettings; - public SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) { + SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) { super(nettyTransport, name, settings); - 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"); + this.profileSsl = PROFILE_SSL_SETTING.exists(profileSettings) ? PROFILE_SSL_SETTING.get(profileSettings) : ssl; + this.profileSslSettings = profileSslSettings(profileSettings); + if (profileSsl && sslService.isConfigurationValidForServerUsage(profileSslSettings, transportSSLSettings) == false) { + if (TransportSettings.DEFAULT_PROFILE.equals(name)) { + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[xpack.security.transport.ssl.key] or [xpack.security.transport.ssl.keystore.path] setting"); + } + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[transport.profiles." + name + ".xpack.security.ssl.key] or [transport.profiles." + name + + ".xpack.security.ssl.keystore.path] setting"); } } @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = super.getPipeline(); - if (sslEnabled) { - SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings); + if (profileSsl) { + final SSLEngine serverEngine = sslService.createSSLEngine(profileSslSettings, transportSSLSettings); serverEngine.setUseClientMode(false); - sslClientAuth.configure(serverEngine); - pipeline.addFirst("ssl", new SslHandler(serverEngine)); } if (authenticator != null) { @@ -194,8 +140,12 @@ public class SecurityNetty3Transport extends Netty3Transport { private class SslClientChannelPipelineFactory extends ClientChannelPipelineFactory { - public SslClientChannelPipelineFactory(Netty3Transport transport) { + private final boolean hostnameVerificationEnabled; + + SslClientChannelPipelineFactory(Netty3Transport transport) { super(transport); + this.hostnameVerificationEnabled = + sslService.getVerificationMode(transportSSLSettings, Settings.EMPTY).isHostnameVerificationEnabled(); } @Override @@ -216,19 +166,13 @@ public class SecurityNetty3Transport extends Netty3Transport { @Override public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) { SSLEngine sslEngine; - if (HOSTNAME_VERIFICATION_SETTING.get(settings)) { + if (hostnameVerificationEnabled) { InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue(); - sslEngine = sslService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress), + // we create the socket based on the name given. don't reverse DNS + sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY, inetSocketAddress.getHostString(), inetSocketAddress.getPort()); - - // By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification - // we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against - // man in the middle attacks for transport connections - SSLParameters parameters = new SSLParameters(); - parameters.setEndpointIdentificationAlgorithm("HTTPS"); - sslEngine.setSSLParameters(parameters); } else { - sslEngine = sslService.createSSLEngine(Settings.EMPTY); + sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY); } sslEngine.setUseClientMode(true); @@ -237,36 +181,6 @@ public class SecurityNetty3Transport extends Netty3Transport { ctx.sendDownstream(e); } - - @SuppressForbidden(reason = "need to use getHostName to resolve DNS name for SSL connections and hostname verification") - private String getHostname(InetSocketAddress inetSocketAddress) { - String hostname; - if (HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.get(settings)) { - hostname = inetSocketAddress.getHostName(); - } else { - hostname = inetSocketAddress.getHostString(); - } - - if (logger.isTraceEnabled()) { - logger.trace("resolved hostname [{}] for address [{}] to be used in ssl hostname verification", hostname, - inetSocketAddress); - } - return hostname; - } } } - - public static void addSettings(List> settingsModule) { - settingsModule.add(SSL_SETTING); - settingsModule.add(HOSTNAME_VERIFICATION_SETTING); - settingsModule.add(HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING); - settingsModule.add(CLIENT_AUTH_SETTING); - settingsModule.add(PROFILE_SSL_SETTING); - settingsModule.add(PROFILE_CLIENT_AUTH_SETTING); - - // deprecated transport settings - settingsModule.add(DEPRECATED_SSL_SETTING); - settingsModule.add(DEPRECATED_PROFILE_SSL_SETTING); - settingsModule.add(DEPRECATED_HOSTNAME_VERIFICATION_SETTING); - } } 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 da33fcff88e..11c907bafd4 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 @@ -13,53 +13,33 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Setting.Property; 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.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import javax.net.ssl.SSLEngine; -import java.util.List; import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION; -import static org.elasticsearch.xpack.security.Security.setting; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException; import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException; +import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport { - public static final boolean SSL_DEFAULT = false; - public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.NO.name(); - - public static final Setting DEPRECATED_SSL_SETTING = - Setting.boolSetting(setting("http.ssl"), SSL_DEFAULT, Property.NodeScope, Property.Deprecated); - public static final Setting SSL_SETTING = - Setting.boolSetting(setting("http.ssl.enabled"), DEPRECATED_SSL_SETTING, Property.NodeScope); - public static final Setting CLIENT_AUTH_SETTING = - new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope); - private final IPFilter ipFilter; private final SSLService sslService; private final boolean ssl; - private final Settings sslSettings; @Inject public SecurityNetty4HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter, SSLService sslService, ThreadPool threadPool) { super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; - this.ssl = SSL_SETTING.get(settings); + this.ssl = HTTP_SSL_ENABLED.get(settings); this.sslService = sslService; - if (ssl) { - sslSettings = settings.getByPrefix(setting("http.ssl.")); - } else { - sslSettings = Settings.EMPTY; - } } @Override @@ -104,13 +84,14 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport private class HttpSslChannelHandler extends HttpChannelHandler { - private final SSLClientAuth clientAuth; + private final Settings sslSettings; 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"); + this.sslSettings = SSLService.getHttpTransportSSLSettings(settings); + if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) { + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting"); } } @@ -118,9 +99,8 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); if (ssl) { - final SSLEngine engine = sslService.createSSLEngine(sslSettings); + final SSLEngine engine = sslService.createSSLEngine(sslSettings, Settings.EMPTY); engine.setUseClientMode(false); - clientAuth.configure(engine); ch.pipeline().addFirst("ssl", new SslHandler(engine)); } ch.pipeline().addFirst("ip_filter", new IpFilterRemoteAddressFilter(ipFilter, IPFilter.HTTP_PROFILE_NAME)); @@ -128,14 +108,8 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport } - public static void addSettings(List> settings) { - settings.add(SSL_SETTING); - settings.add(CLIENT_AUTH_SETTING); - settings.add(DEPRECATED_SSL_SETTING); - } - public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) { - if (SSL_SETTING.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) { + if (HTTP_SSL_ENABLED.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) { 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 4d3f40f7bd4..64654218a2f 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 @@ -11,30 +11,27 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import io.netty.handler.ssl.SslHandler; -import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.settings.Setting; -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.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.transport.netty4.Netty4Transport; -import org.elasticsearch.xpack.security.ssl.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLParameters; import java.net.InetSocketAddress; import java.net.SocketAddress; import static org.elasticsearch.xpack.security.Security.setting; -import static org.elasticsearch.xpack.security.Security.settingPrefix; +import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED; /** @@ -42,58 +39,11 @@ import static org.elasticsearch.xpack.security.Security.settingPrefix; */ public class SecurityNetty4Transport extends Netty4Transport { - public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name(); - public static final boolean SSL_DEFAULT = false; - - public static final Setting DEPRECATED_HOSTNAME_VERIFICATION_SETTING = - Setting.boolSetting( - setting("ssl.hostname_verification"), - true, - new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared}); - - public static final Setting HOSTNAME_VERIFICATION_SETTING = - Setting.boolSetting(setting("ssl.hostname_verification.enabled"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING, - Property.NodeScope, Property.Filtered, Property.Shared); - - public static final Setting HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING = - Setting.boolSetting( - setting("ssl.hostname_verification.resolve_name"), - true, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - - public static final Setting DEPRECATED_SSL_SETTING = - Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT, - Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared); - - public static final Setting SSL_SETTING = - Setting.boolSetting( - setting("transport.ssl.enabled"), - DEPRECATED_SSL_SETTING, - new Property[]{Property.Filtered, Property.NodeScope, Property.Shared}); - - public static final Setting CLIENT_AUTH_SETTING = - new Setting<>( - setting("transport.ssl.client.auth"), - CLIENT_AUTH_DEFAULT, - SSLClientAuth::parse, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); - - public static final Setting DEPRECATED_PROFILE_SSL_SETTING = - Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared); - - public static final Setting PROFILE_SSL_SETTING = - Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared); - - public static final Setting PROFILE_CLIENT_AUTH_SETTING = - new Setting<>( - setting("ssl.client.auth"), - CLIENT_AUTH_SETTING, - SSLClientAuth::parse, - new Property[]{Property.NodeScope, Property.Filtered, Property.Shared}); + private static final Setting PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false); private final SSLService sslService; @Nullable private final IPFilter authenticator; - private final SSLClientAuth clientAuth; + private final Settings transportSSLSettings; private final boolean ssl; @Inject @@ -102,9 +52,9 @@ public class SecurityNetty4Transport extends Netty4Transport { @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.ssl = TRANSPORT_SSL_ENABLED.get(settings); this.sslService = sslService; + this.transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); } @Override @@ -130,12 +80,18 @@ public class SecurityNetty4Transport extends Netty4Transport { 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"); + SecurityServerChannelInitializer(String name, Settings profileSettings) { + super(name, profileSettings); + this.sslEnabled = PROFILE_SSL_SETTING.exists(profileSettings) ? PROFILE_SSL_SETTING.get(profileSettings) : ssl; + this.securityProfileSettings = profileSettings.getByPrefix(setting("ssl.")); + if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings, transportSSLSettings) == false) { + if (TransportSettings.DEFAULT_PROFILE.equals(name)) { + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[xpack.security.transport.ssl.key] or [xpack.security.transport.ssl.keystore.path] setting"); + } + throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " + + "[transport.profiles." + name + ".xpack.security.ssl.key] or [transport.profiles." + name + + ".xpack.security.ssl.keystore.path] setting"); } } @@ -143,10 +99,8 @@ public class SecurityNetty4Transport extends Netty4Transport { protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); if (sslEnabled) { - SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings); + SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings, transportSSLSettings); serverEngine.setUseClientMode(false); - final SSLClientAuth profileClientAuth = profileClientAuth(settings, clientAuth); - profileClientAuth.configure(serverEngine); ch.pipeline().addFirst(new SslHandler(serverEngine)); } if (authenticator != null) { @@ -155,72 +109,52 @@ public class SecurityNetty4Transport extends Netty4Transport { } } - class SecurityClientChannelInitializer extends ClientChannelInitializer { + private class SecurityClientChannelInitializer extends ClientChannelInitializer { + + private final boolean hostnameVerificationEnabled; + + SecurityClientChannelInitializer() { + this.hostnameVerificationEnabled = + sslService.getVerificationMode(transportSSLSettings, Settings.EMPTY).isHostnameVerificationEnabled(); + } + @Override protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); if (ssl) { - ch.pipeline().addFirst(new ClientSslHandlerInitializer()); + ch.pipeline().addFirst(new ClientSslHandlerInitializer(transportSSLSettings, sslService, hostnameVerificationEnabled)); } } } - private class ClientSslHandlerInitializer extends ChannelOutboundHandlerAdapter { + private static class ClientSslHandlerInitializer extends ChannelOutboundHandlerAdapter { + + private final boolean hostnameVerificationEnabled; + private final Settings sslSettings; + private final SSLService sslService; + + private ClientSslHandlerInitializer(Settings sslSettings, SSLService sslService, boolean hostnameVerificationEnabled) { + this.sslSettings = sslSettings; + this.hostnameVerificationEnabled = hostnameVerificationEnabled; + this.sslService = sslService; + } @Override public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { final SSLEngine sslEngine; - if (HOSTNAME_VERIFICATION_SETTING.get(settings)) { + if (hostnameVerificationEnabled) { InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress; - 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 - // man in the middle attacks for transport connections - SSLParameters parameters = new SSLParameters(); - parameters.setEndpointIdentificationAlgorithm("HTTPS"); - sslEngine.setSSLParameters(parameters); + // we create the socket based on the name given. don't reverse DNS + sslEngine = sslService.createSSLEngine(sslSettings, Settings.EMPTY, inetSocketAddress.getHostString(), + inetSocketAddress.getPort()); } else { - sslEngine = sslService.createSSLEngine(Settings.EMPTY); + sslEngine = sslService.createSSLEngine(sslSettings, Settings.EMPTY); } sslEngine.setUseClientMode(true); ctx.pipeline().replace(this, "ssl", new SslHandler(sslEngine)); super.connect(ctx, remoteAddress, localAddress, promise); } - - @SuppressForbidden(reason = "need to use getHostName to resolve DNS name for SSL connections and hostname verification") - private String getHostname(InetSocketAddress inetSocketAddress) { - String hostname; - if (HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.get(settings)) { - hostname = inetSocketAddress.getHostName(); - } else { - hostname = inetSocketAddress.getHostString(); - } - - if (logger.isTraceEnabled()) { - logger.trace("resolved hostname [{}] for address [{}] to be used in ssl hostname verification", hostname, - inetSocketAddress); - } - return hostname; - } - } - - 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)) { - return DEPRECATED_PROFILE_SSL_SETTING.get(profileSettings); - } else { - return defaultSSL; - } - } - - static SSLClientAuth profileClientAuth(Settings settings, SSLClientAuth clientAuth) { - if (PROFILE_CLIENT_AUTH_SETTING.exists(settings)) { - return PROFILE_CLIENT_AUTH_SETTING.get(settings); - } - return clientAuth; } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java index 62472065fde..b4777b63c9b 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java @@ -17,7 +17,6 @@ import org.elasticsearch.xpack.security.authc.activedirectory.ActiveDirectoryRea import org.elasticsearch.xpack.security.authc.ldap.LdapRealm; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -32,7 +31,6 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile; import static org.hamcrest.Matchers.equalTo; - /** * This test assumes all subclass tests will be of type SUITE. It picks a random realm configuration for the tests, and * writes a group to role mapping file for each node. @@ -165,11 +163,11 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase private Settings sslSettingsForStore(Path store, String password) { return Settings.builder() - .put("xpack.security.ssl.keystore.path", store) - .put("xpack.security.ssl.keystore.password", password) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false) - .put("xpack.security.ssl.truststore.path", store) - .put("xpack.security.ssl.truststore.password", password).build(); + .put("xpack.ssl.keystore.path", store) + .put("xpack.ssl.keystore.password", password) + .put("xpack.ssl.verification_mode", "certificate") + .put("xpack.ssl.truststore.path", store) + .put("xpack.ssl.truststore.password", password).build(); } /** diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java index 3b838c56fc5..1a60747cd93 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java @@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.support.SecuredString; @@ -23,7 +24,6 @@ import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode; import org.elasticsearch.xpack.XPackClient; import org.elasticsearch.xpack.XPackPlugin; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -377,7 +377,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { final List nodes = nodeInfos.getNodes(); assertTrue("there is at least one node", nodes.size() > 0); NodeInfo ni = randomFrom(nodes); - boolean useSSL = SecurityNetty3HttpServerTransport.SSL_SETTING.get(ni.getSettings()); + boolean useSSL = XPackSettings.HTTP_SSL_ENABLED.get(ni.getSettings()); TransportAddress publishAddress = ni.getHttp().address().publishAddress(); assertEquals(1, publishAddress.uniqueAddressTypeId()); InetSocketAddress address = ((InetSocketTransportAddress) publishAddress).address(); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index 1e8ad5a1414..1f0610373d1 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -25,8 +25,6 @@ import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.test.SecurityTestUtils; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration; import org.elasticsearch.xpack.XPackPlugin; @@ -36,11 +34,9 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean; -import static org.elasticsearch.test.ESTestCase.randomFrom; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile; @@ -87,7 +83,6 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas private final byte[] systemKey; private final boolean sslTransportEnabled; private final boolean hostnameVerificationEnabled; - private final boolean hostnameVerificationResolveNameEnabled; /** * Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration. @@ -117,7 +112,6 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas this.subfolderPrefix = scope.name(); this.sslTransportEnabled = sslTransportEnabled; this.hostnameVerificationEnabled = randomBoolean(); - this.hostnameVerificationResolveNameEnabled = randomBoolean(); } @Override @@ -218,29 +212,29 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas public Settings getNodeSSLSettings() { if (randomBoolean()) { return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", - Collections.singletonList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/openldap.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), - sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false); + sslTransportEnabled, hostnameVerificationEnabled, false); } return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode", - sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false); + sslTransportEnabled, hostnameVerificationEnabled, false); } public Settings getClientSSLSettings() { if (randomBoolean()) { return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem", "testclient", - Collections.singletonList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), - sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true); + sslTransportEnabled, hostnameVerificationEnabled, true); } return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient", - sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true); + sslTransportEnabled, hostnameVerificationEnabled, true); } /** @@ -251,67 +245,57 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas * @return the configuration settings */ public static Settings getSSLSettingsForStore(String resourcePathToStore, String password) { - return getSSLSettingsForStore(resourcePathToStore, password, true, true, true, true); + return getSSLSettingsForStore(resourcePathToStore, password, true, true, true); } private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled, - boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled, - boolean transportClient) { + boolean hostnameVerificationEnabled, boolean transportClient) { Path store = resolveResourcePath(resourcePathToStore); - final String sslEnabledSetting = - randomFrom(SecurityNetty3Transport.SSL_SETTING.getKey(), SecurityNetty3Transport.DEPRECATED_SSL_SETTING.getKey()); - Settings.Builder builder = Settings.builder().put(sslEnabledSetting, sslTransportEnabled); + Settings.Builder builder = Settings.builder().put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled); if (transportClient == false) { - builder.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false); + builder.put("xpack.security.http.ssl.enabled", false); } if (sslTransportEnabled) { - builder.put("xpack.security.ssl.keystore.path", store) - .put("xpack.security.ssl.keystore.password", password) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), hostnameVerificationEnabled) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), - hostnameVerificationResolveNameEnabled); + builder.put("xpack.ssl.keystore.path", store) + .put("xpack.ssl.keystore.password", password) + .put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); } if (sslTransportEnabled && randomBoolean()) { - builder.put("xpack.security.ssl.truststore.path", store) - .put("xpack.security.ssl.truststore.password", password); + builder.put("xpack.ssl.truststore.path", store) + .put("xpack.ssl.truststore.password", password); } return builder.build(); } - private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, List certificateFiles, + private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, String certificatePath, List trustedCertificates, boolean sslTransportEnabled, - boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled, - boolean transportClient) { + boolean hostnameVerificationEnabled, boolean transportClient) { Settings.Builder builder = Settings.builder(); - final String sslEnabledSetting = - randomFrom(SecurityNetty3Transport.SSL_SETTING.getKey(), SecurityNetty3Transport.DEPRECATED_SSL_SETTING.getKey()); - builder.put(sslEnabledSetting, sslTransportEnabled); + builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled); if (transportClient == false) { - builder.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false); + builder.put("xpack.security.http.ssl.enabled", false); } if (sslTransportEnabled) { - builder.put("xpack.security.ssl.key.path", resolveResourcePath(keyPath)) - .put("xpack.security.ssl.key.password", password) - .put("xpack.security.ssl.cert", Strings.arrayToCommaDelimitedString(resolvePathsToString(certificateFiles))) - .put(randomFrom(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), - SecurityNetty3Transport.DEPRECATED_HOSTNAME_VERIFICATION_SETTING.getKey()), hostnameVerificationEnabled) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), - hostnameVerificationResolveNameEnabled); + builder.put("xpack.ssl.key", resolveResourcePath(keyPath)) + .put("xpack.ssl.key_passphrase", password) + .put("xpack.ssl.certificate", resolveResourcePath(certificatePath)) + .put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); if (trustedCertificates.isEmpty() == false) { - builder.put("xpack.security.ssl.ca", Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates))); + builder.put("xpack.ssl.certificate_authorities", + Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates))); } } return builder.build(); } - static String[] resolvePathsToString(List resourcePaths) { + private static String[] resolvePathsToString(List resourcePaths) { List resolvedPaths = new ArrayList<>(resourcePaths.size()); for (String resource : resourcePaths) { resolvedPaths.add(resolveResourcePath(resource).toString()); @@ -319,7 +303,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas return resolvedPaths.toArray(new String[resolvedPaths.size()]); } - static Path resolveResourcePath(String resourcePathToStore) { + private static Path resolveResourcePath(String resourcePathToStore) { try { Path path = PathUtils.get(SecuritySettingsSource.class.getResource(resourcePathToStore).toURI()); if (Files.notExists(path)) { 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 830361379a5..e5323d315b5 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 @@ -5,6 +5,7 @@ */ package org.elasticsearch.test; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Guice; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.Setting; @@ -12,8 +13,11 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.xpack.XPackPlugin; +import org.elasticsearch.xpack.XPackSettings; import org.hamcrest.Matcher; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -53,26 +57,32 @@ public class SettingsFilterTests extends ESTestCase { configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.password", "truststore-testnode-only"); configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.algorithm", "SunX509"); - configureFilteredSetting("xpack.security.ssl.keystore.path", "/path/to/keystore"); - configureFilteredSetting("xpack.security.ssl.ciphers", "_ciphers"); - 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)); - configureFilteredSetting("xpack.security.ssl.truststore.password", randomAsciiOfLength(5)); - configureFilteredSetting("xpack.security.ssl.truststore.algorithm", "_algorithm"); + configureFilteredSetting("xpack.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString()); + configureFilteredSetting("xpack.ssl.cipher_suites", + Strings.arrayToCommaDelimitedString(XPackSettings.DEFAULT_CIPHERS.toArray())); + configureFilteredSetting("xpack.ssl.supported_protocols", randomFrom("TLSv1", "TLSv1.1", "TLSv1.2")); + configureFilteredSetting("xpack.ssl.keystore.password", "testnode"); + configureFilteredSetting("xpack.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm()); + configureFilteredSetting("xpack.ssl.keystore.key_password", "testnode"); + configureFilteredSetting("xpack.ssl.truststore.password", randomAsciiOfLength(5)); + configureFilteredSetting("xpack.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm()); // client profile configureUnfilteredSetting("transport.profiles.client.port", "9500-9600"); - 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", + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString()); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.cipher_suites", + Strings.arrayToCommaDelimitedString(XPackSettings.DEFAULT_CIPHERS.toArray())); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.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)); - configureFilteredSetting("transport.profiles.client.xpack.security.truststore.password", randomAsciiOfLength(5)); - configureFilteredSetting("transport.profiles.client.xpack.security.truststore.algorithm", "_algorithm"); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.password", "testnode"); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.algorithm", + KeyManagerFactory.getDefaultAlgorithm()); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.key_password", "testnode"); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.truststore.password", randomAsciiOfLength(5)); + configureFilteredSetting("transport.profiles.client.xpack.security.ssl.truststore.algorithm", + TrustManagerFactory.getDefaultAlgorithm()); // custom settings, potentially added by a plugin configureFilteredSetting("foo.bar", "_secret"); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java index 83a017bcd40..38df2751180 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java @@ -22,8 +22,6 @@ import org.elasticsearch.xpack.security.authc.Realms; import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore; import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.xpack.security.user.AnonymousUser; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.junit.After; @@ -111,9 +109,9 @@ public class SecurityFeatureSetTests extends ESTestCase { settings.put("xpack.security.enabled", enabled); final boolean httpSSLEnabled = randomBoolean(); - settings.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), httpSSLEnabled); + settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled); final boolean transportSSLEnabled = randomBoolean(); - settings.put(SecurityNetty3Transport.SSL_SETTING.getKey(), transportSSLEnabled); + settings.put("xpack.security.transport.ssl.enabled", transportSSLEnabled); final boolean auditingEnabled = randomBoolean(); final String[] auditOutputs = randomFrom(new String[] {"logfile"}, new String[] {"index"}, new String[] {"logfile", "index"}); when(auditTrail.usageStats()) diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index b7a9f195cc8..3e28f984873 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -31,6 +31,7 @@ import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.Realms; import org.elasticsearch.xpack.security.authc.file.FileRealm; +import org.elasticsearch.xpack.ssl.SSLService; import static org.hamcrest.Matchers.containsString; import static org.mockito.Mockito.mock; @@ -61,7 +62,7 @@ public class SecurityTests extends ESTestCase { Settings settings = Settings.builder().put(testSettings) .put("path.home", createTempDir()).build(); Environment env = new Environment(settings); - Security security = new Security(settings, env, new XPackLicenseState()); + Security security = new Security(settings, env, new XPackLicenseState(), new SSLService(settings, env)); ThreadPool threadPool = mock(ThreadPool.class); ClusterService clusterService = mock(ClusterService.class); settings = Security.additionalSettings(settings, false); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java index 6ed3520f046..b5baf410824 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java @@ -173,7 +173,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue()); } } else { - builder.put("xpack.security.audit.index.client." + SecurityNetty3Transport.SSL_SETTING.getKey(), false); + builder.put("xpack.security.audit.index.client.xpack.ssl.client_authentication", "none"); } remoteSettings = builder.build(); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java index fe9ce7eb91f..e756ff6aabc 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java @@ -20,7 +20,6 @@ import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.XPackTransportClient; @@ -229,7 +228,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(extraSettings) .put("cluster.name", clusterName) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), false) + .put("xpack.security.transport.ssl.enabled", false) .build(); return new XPackTransportClient(settings) 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 9c6489908b8..6cf6d67bb38 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 @@ -10,7 +10,7 @@ import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; -import org.elasticsearch.xpack.security.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.Before; import java.nio.file.Path; @@ -37,8 +37,8 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase { */ Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); if (useGlobalSSL) { - builder.put("xpack.security.ssl.keystore.path", keystore) - .put("xpack.security.ssl.keystore.password", "changeit"); + builder.put("xpack.ssl.keystore.path", keystore) + .put("xpack.ssl.keystore.password", "changeit"); } else { // fake a realm so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryGroupsResolverTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryGroupsResolverTests.java index 2a02e94af60..8e821d4b385 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryGroupsResolverTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/activedirectory/ActiveDirectoryGroupsResolverTests.java @@ -24,7 +24,7 @@ import static org.hamcrest.Matchers.is; @Network public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase { - public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; + private static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"; public void testResolveSubTree() throws Exception { Settings settings = Settings.builder() diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java index 59ed23be55e..2d33333eb02 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java @@ -44,7 +44,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase { Settings s = Settings.builder() .put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), useSSL) + .put("xpack.security.http.ssl.enabled", useSSL) .build(); return s; } 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 3791ff8906d..c8b4718c60c 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 @@ -12,7 +12,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.security.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.After; import org.junit.Before; @@ -34,8 +34,8 @@ public abstract class GroupsResolverTestCase extends ESTestCase { boolean useGlobalSSL = randomBoolean(); Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); if (useGlobalSSL) { - builder.put("xpack.security.ssl.keystore.path", keystore) - .put("xpack.security.ssl.keystore.password", "changeit"); + builder.put("xpack.ssl.keystore.path", keystore) + .put("xpack.ssl.keystore.password", "changeit"); } else { // fake a realm so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.keystore.path", keystore); 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 3cf8ddd03e8..a9ba816e4a7 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,7 +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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.support.NoOpLogger; import org.elasticsearch.test.junit.annotations.Network; import org.junit.Before; @@ -59,8 +59,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { */ globalSettings = Settings.builder() .put("path.home", createTempDir()) - .put("xpack.security.ssl.keystore.path", keystore) - .put("xpack.security.ssl.keystore.password", "changeit") + .put("xpack.ssl.keystore.path", keystore) + .put("xpack.ssl.keystore.password", "changeit") .build(); sslService = new SSLService(globalSettings, env); } 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 dacf3231201..37a9648b21f 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 @@ -16,7 +16,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; -import org.elasticsearch.xpack.security.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.Before; import java.nio.file.Path; @@ -46,8 +46,8 @@ public class OpenLdapTests extends ESTestCase { useGlobalSSL = randomBoolean(); Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); if (useGlobalSSL) { - builder.put("xpack.security.ssl.keystore.path", keystore) - .put("xpack.security.ssl.keystore.password", "changeit"); + builder.put("xpack.ssl.keystore.path", keystore) + .put("xpack.ssl.keystore.password", "changeit"); } else { // fake a realm so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore); 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 e34b71a7239..2e4677fa86f 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.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import java.util.ArrayList; import java.util.Arrays; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java index 84eeae70802..4ab41345245 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java @@ -21,8 +21,7 @@ import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.file.FileRealm; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; @@ -57,8 +56,8 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { .put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), sslClientAuth) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", sslClientAuth) .put("xpack.security.authc.realms.file.type", FileRealm.TYPE) .put("xpack.security.authc.realms.file.order", "0") .put("xpack.security.authc.realms.pki1.type", PkiRealm.TYPE) @@ -141,10 +140,10 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { private TransportClient createTransportClient(Settings additionalSettings) { Settings clientSettings = transportClientSettings(); - if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) { + if (additionalSettings.getByPrefix("xpack.ssl.").isEmpty() == false) { Settings.Builder builder = Settings.builder(); for (Entry entry : clientSettings.getAsMap().entrySet()) { - if (entry.getKey().startsWith("xpack.security.ssl.") == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { builder.put(entry.getKey(), entry.getValue()); } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java index 58b15f5a289..9e2ce4e0bf8 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java @@ -21,9 +21,7 @@ import org.elasticsearch.xpack.XPackTransportClient; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.junit.BeforeClass; import javax.net.ssl.SSLContext; @@ -56,8 +54,8 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { return Settings.builder() .put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), SSLClientAuth.OPTIONAL) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", SSLClientAuth.OPTIONAL) .put("xpack.security.authc.realms.file.type", "file") .put("xpack.security.authc.realms.file.order", "0") .put("xpack.security.authc.realms.pki1.type", "pki") @@ -68,7 +66,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { .put("xpack.security.authc.realms.pki1.files.role_mapping", getDataPath("role_mapping.yml")) .put("transport.profiles.want_client_auth.port", randomClientPortRange) .put("transport.profiles.want_client_auth.bind_host", "localhost") - .put("transport.profiles.want_client_auth.xpack.security.ssl.client.auth", SSLClientAuth.OPTIONAL) + .put("transport.profiles.want_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.OPTIONAL) .build(); } @@ -106,7 +104,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { .put(sslSettingsForStore) .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .build(); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java index 5fbba1c04b1..2ecefa36944 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java @@ -7,6 +7,9 @@ package org.elasticsearch.xpack.security.authc.pki; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.env.Environment; +import org.elasticsearch.xpack.ssl.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.authc.RealmConfig; import org.elasticsearch.xpack.security.authc.support.DnRoleMapper; @@ -35,16 +38,25 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class PkiRealmTests extends ESTestCase { + private Settings globalSettings; + private SSLService sslService; @Before public void setup() { - globalSettings = Settings.builder().put("path.home", createTempDir()).build(); + Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); + globalSettings = Settings.builder() + .put("path.home", createTempDir()) + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") + .put("xpack.security.transport.ssl.enabled", true) + .build(); + sslService = new SSLService(globalSettings, new Environment(globalSettings)); } public void testTokenSupport() { RealmConfig config = new RealmConfig("", Settings.EMPTY, globalSettings); - PkiRealm realm = new PkiRealm(config, mock(DnRoleMapper.class)); + PkiRealm realm = new PkiRealm(config, mock(DnRoleMapper.class), sslService); assertThat(realm.supports(null), is(false)); assertThat(realm.supports(new UsernamePasswordToken("", new SecuredString(new char[0]))), is(false)); @@ -55,7 +67,7 @@ public class PkiRealmTests extends ESTestCase { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); - PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class)); + PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class), sslService); X509AuthenticationToken token = realm.token(threadContext); assertThat(token, is(notNullValue())); @@ -68,7 +80,7 @@ public class PkiRealmTests extends ESTestCase { X509AuthenticationToken token = new X509AuthenticationToken(new X509Certificate[] { certificate }, "Elasticsearch Test Node", "CN=Elasticsearch Test Node,"); DnRoleMapper roleMapper = mock(DnRoleMapper.class); - PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), roleMapper); + PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), roleMapper, sslService); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); User user = realm.authenticate(token); @@ -82,7 +94,7 @@ public class PkiRealmTests extends ESTestCase { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); DnRoleMapper roleMapper = mock(DnRoleMapper.class); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings), - roleMapper); + roleMapper, sslService); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); @@ -102,7 +114,7 @@ public class PkiRealmTests extends ESTestCase { .put("truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) .put("truststore.password", "testnode") .build(); - PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper); + PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper, sslService); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); @@ -124,7 +136,7 @@ public class PkiRealmTests extends ESTestCase { getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) .put("truststore.password", "testnode-client-profile") .build(); - PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper); + PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper, sslService); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); @@ -141,10 +153,10 @@ public class PkiRealmTests extends ESTestCase { getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) .build(); try { - new PkiRealm(new RealmConfig("", settings, globalSettings), mock(DnRoleMapper.class)); + new PkiRealm(new RealmConfig("mypki", settings, globalSettings), mock(DnRoleMapper.class), sslService); fail("exception should have been thrown"); } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), containsString("no truststore password configured")); + assertThat(e.getMessage(), containsString("[xpack.security.authc.realms.mypki.truststore.password] is not configured")); } } @@ -184,6 +196,41 @@ public class PkiRealmTests extends ESTestCase { assertThat(token.dn(), is("EMAILADDRESS=pki@elastic.co, CN=PKI Client, OU=Security")); } + public void testNoClientAuthThrowsException() throws Exception { + Settings settings = Settings.builder() + .put(globalSettings) + .put("xpack.ssl.client_authentication", "none") + .build(); + + IllegalStateException e = expectThrows(IllegalStateException.class, + () -> new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class), + new SSLService(settings, new Environment(settings)))); + assertThat(e.getMessage(), containsString("has SSL with client authentication enabled")); + } + + public void testHttpClientAuthOnly() { + Settings settings = Settings.builder() + .put(globalSettings) + .put("xpack.ssl.client_authentication", "none") + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", randomFrom(SSLClientAuth.OPTIONAL, SSLClientAuth.REQUIRED)) + .build(); + new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class), + new SSLService(settings, new Environment(settings))); + } + + public void testNoSSLThrowsException() throws Exception { + Settings settings = Settings.builder() + .put(globalSettings) + .put("xpack.security.transport.ssl.enabled", false) + .build(); + + IllegalStateException e = expectThrows(IllegalStateException.class, + () -> new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class), + new SSLService(settings, new Environment(settings)))); + assertThat(e.getMessage(), containsString("has SSL with client authentication enabled")); + } + static X509Certificate readCert(Path path) throws Exception { try (InputStream in = Files.newInputStream(path)) { CertificateFactory factory = CertificateFactory.getInstance("X.509"); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutClientAuthenticationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutClientAuthenticationTests.java deleted file mode 100644 index 7a21022f6e8..00000000000 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutClientAuthenticationTests.java +++ /dev/null @@ -1,89 +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.authc.pki; - - -import org.apache.http.message.BasicHeader; -import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; -import org.elasticsearch.client.Client; -import org.elasticsearch.client.Response; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.common.network.NetworkModule; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.test.ESIntegTestCase.ClusterScope; -import org.elasticsearch.test.SecurityIntegTestCase; -import org.elasticsearch.test.SecuritySettingsSource; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.util.Locale; - -import static org.hamcrest.Matchers.is; - -@ClusterScope(numClientNodes = 0, supportsDedicatedMasters = false, numDataNodes = 1) -public class PkiWithoutClientAuthenticationTests extends SecurityIntegTestCase { - private TrustManager[] trustAllCerts = new TrustManager[] { - new X509TrustManager() { - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - @Override - public void checkClientTrusted(X509Certificate[] certs, String authType) { - } - - @Override - public void checkServerTrusted(X509Certificate[] certs, String authType) { - } - } - }; - - @Override - public boolean sslTransportEnabled() { - return true; - } - - @Override - public Settings nodeSettings(int nodeOrdinal) { - return Settings.builder() - .put(super.nodeSettings(nodeOrdinal)) - .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), false) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), - randomFrom(SSLClientAuth.NO.name(), false, "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT))) - .put("xpack.security.authc.realms.pki1.type", "pki") - .put("xpack.security.authc.realms.pki1.order", "0") - .build(); - } - - public void testThatTransportClientWorks() { - Client client = internalCluster().transportClient(); - assertGreenClusterState(client); - } - - public void testThatHttpWorks() throws Exception { - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, new SecureRandom()); - SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sc); - try (RestClient restClient = createRestClient(httpClientBuilder -> httpClientBuilder.setSSLStrategy(sessionStrategy), "https")) { - Response response = restClient.performRequest("GET", "/_nodes", - new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, - UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, - new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())))); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - } - } -} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutSSLTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutSSLTests.java deleted file mode 100644 index 375acafc2cf..00000000000 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiWithoutSSLTests.java +++ /dev/null @@ -1,50 +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.authc.pki; - -import org.apache.http.message.BasicHeader; -import org.elasticsearch.client.Client; -import org.elasticsearch.client.Response; -import org.elasticsearch.common.network.NetworkModule; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.test.ESIntegTestCase.ClusterScope; -import org.elasticsearch.test.SecurityIntegTestCase; -import org.elasticsearch.test.SecuritySettingsSource; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; - -import static org.hamcrest.Matchers.is; - -@ClusterScope(numClientNodes = 0, supportsDedicatedMasters = false, numDataNodes = 1) -public class PkiWithoutSSLTests extends SecurityIntegTestCase { - @Override - public boolean sslTransportEnabled() { - return false; - } - - @Override - public Settings nodeSettings(int nodeOrdinal) { - return Settings.builder() - .put(super.nodeSettings(nodeOrdinal)) - .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put("xpack.security.authc.realms.pki1.type", "pki") - .put("xpack.security.authc.realms.pki1.order", "0") - .build(); - } - - public void testThatTransportClientWorks() { - Client client = internalCluster().transportClient(); - assertGreenClusterState(client); - } - - public void testThatHttpWorks() throws Exception { - Response response = getRestClient().performRequest("GET", "/_nodes", - new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, - UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, - new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())))); - assertThat(response.getStatusLine().getStatusCode(), is(200)); - } -} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java index c693add0a6a..e732ea4156e 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java @@ -17,6 +17,7 @@ import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.Before; import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError; @@ -46,7 +47,7 @@ public class SecurityRestFilterTests extends ESTestCase { when(licenseState.isAuthAllowed()).thenReturn(true); ThreadPool threadPool = mock(ThreadPool.class); when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); - filter = new SecurityRestFilter(authcService, restController, Settings.EMPTY, threadPool, licenseState); + filter = new SecurityRestFilter(authcService, restController, Settings.EMPTY, threadPool, licenseState, mock(SSLService.class)); verify(restController).registerFilter(filter); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java index cfc487feddf..adb1fc7ee4b 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java @@ -19,7 +19,7 @@ import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.file.FileRealm; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.junit.BeforeClass; import java.io.IOException; @@ -64,7 +64,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase if (sslTransportEnabled()) { settingsBuilder.put("transport.profiles.client.xpack.security.truststore.path", store) // settings for client truststore .put("transport.profiles.client.xpack.security.truststore.password", "testnode") - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true); + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED); } return settingsBuilder @@ -97,7 +97,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase .put("network.host", "localhost") .put("cluster.name", internalCluster().getClusterName()) .put("discovery.zen.ping.unicast.hosts", unicastHost) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), sslTransportEnabled()) + .put("xpack.security.transport.ssl.enabled", sslTransportEnabled()) .put("xpack.security.audit.enabled", false) .put("path.home", home) .put(NetworkModule.HTTP_ENABLED.getKey(), false) @@ -133,7 +133,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase .put(Security.USER_SETTING.getKey(), "test_user:changeme") .put("cluster.name", internalCluster().getClusterName()) .put("discovery.zen.ping.unicast.hosts", "localhost:" + randomClientPort) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), sslTransportEnabled()) + .put("xpack.security.transport.ssl.enabled", sslTransportEnabled()) .put("xpack.security.audit.enabled", false) .put(NetworkModule.HTTP_ENABLED.getKey(), false) .put("discovery.initial_state_timeout", "2s") diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java index 1697eda141f..6315f743abf 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.transport.TransportResponseHandler; import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.xpack.security.user.SystemUser; +import org.elasticsearch.xpack.ssl.SSLService; import org.mockito.InOrder; import java.io.IOException; @@ -287,7 +288,8 @@ public class TransportFilterTests extends ESIntegTestCase { public InternalPluginServerTransportService(Settings settings, Transport transport, ThreadPool threadPool, AuthenticationService authcService, AuthorizationService authzService, SecurityActionMapper actionMapper) { - super(settings, transport, threadPool, authcService, authzService, actionMapper, mock(XPackLicenseState.class)); + super(settings, transport, threadPool, authcService, authzService, actionMapper, mock(XPackLicenseState.class), + mock(SSLService.class)); when(licenseState.isAuthAllowed()).thenReturn(true); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/IPHostnameVerificationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/IPHostnameVerificationTests.java index 91333bf42c4..1d72b5d800d 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/IPHostnameVerificationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/IPHostnameVerificationTests.java @@ -9,6 +9,7 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.TransportSettings; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import java.nio.file.Files; import java.nio.file.Path; @@ -16,6 +17,7 @@ import java.util.Map.Entry; import static org.hamcrest.CoreMatchers.is; +// TODO delete this test? public class IPHostnameVerificationTests extends SecurityIntegTestCase { Path keystore; @@ -29,7 +31,7 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { Settings settings = super.nodeSettings(nodeOrdinal); Settings.Builder builder = Settings.builder(); for (Entry entry : settings.getAsMap().entrySet()) { - if (entry.getKey().startsWith("xpack.security.ssl.") == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { builder.put(entry.getKey(), entry.getValue()); } } @@ -54,15 +56,14 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { throw new RuntimeException(e); } - return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore - .put("xpack.security.ssl.keystore.password", "testnode-ip-only") - .put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore - .put("xpack.security.ssl.truststore.password", "testnode-ip-only") + return settingsBuilder.put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore + .put("xpack.ssl.keystore.password", "testnode-ip-only") + .put("xpack.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore + .put("xpack.ssl.truststore.password", "testnode-ip-only") .put(TransportSettings.BIND_HOST.getKey(), "127.0.0.1") .put("network.host", "127.0.0.1") - .put("xpack.security.ssl.client.auth", "false") - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), false) + .put("xpack.ssl.client_authentication", SSLClientAuth.NONE) + .put("xpack.ssl.verification_mode", "full") .build(); } @@ -71,19 +72,18 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { Settings clientSettings = super.transportClientSettings(); Settings.Builder builder = Settings.builder(); for (Entry entry : clientSettings.getAsMap().entrySet()) { - if (entry.getKey().startsWith("xpack.security.ssl.") == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { builder.put(entry.getKey(), entry.getValue()); } } clientSettings = builder.build(); return Settings.builder().put(clientSettings) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), false) - .put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) - .put("xpack.security.ssl.keystore.password", "testnode-ip-only") - .put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) - .put("xpack.security.ssl.truststore.password", "testnode-ip-only") + .put("xpack.ssl.verification_mode", "certificate") + .put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) + .put("xpack.ssl.keystore.password", "testnode-ip-only") + .put("xpack.ssl.truststore.path", keystore.toAbsolutePath()) + .put("xpack.ssl.truststore.password", "testnode-ip-only") .build(); } 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 96d05ffc8d2..a097117ea98 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 @@ -9,7 +9,7 @@ import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.security.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLService; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; @@ -69,9 +69,9 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { iterations = randomIntBetween(10, 100); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", + .put("xpack.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.password", "testnode") .build(); Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); sslService = new SSLService(settings, env); @@ -100,7 +100,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); + final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); engine.setUseClientMode(true); return Channels.pipeline( new SslHandler(engine)); @@ -137,7 +137,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); + final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); engine.setUseClientMode(true); return Channels.pipeline( new SslHandler(engine), @@ -208,7 +208,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase { return new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { - final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); + final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, 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 f5d08ddbb3f..d338e36a9fd 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,8 @@ 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.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; @@ -40,8 +40,8 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void createSSLService() throws Exception { Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -49,7 +49,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { } public void testDefaultClientAuth() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.http.ssl.enabled", true).build(); + sslService = new SSLService(settings, env); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -61,8 +64,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", value).build(); + sslService = new SSLService(settings, env); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -72,10 +77,11 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { } public void testRequiredClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE"); Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", SSLClientAuth.REQUIRED).build(); + sslService = new SSLService(settings, env); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -85,10 +91,11 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { } public void testNoClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.NO.name(), SSLClientAuth.NO.name().toLowerCase(Locale.ROOT), "false", "FALSE"); Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", SSLClientAuth.NONE).build(); + sslService = new SSLService(settings, env); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -99,7 +106,9 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testCustomSSLConfiguration() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); + .put(env.settings()) + .put("xpack.security.http.ssl.enabled", true).build(); + sslService = new SSLService(settings, env); SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -108,7 +117,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { settings = Settings.builder() .put(env.settings()) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) + .put("xpack.security.http.ssl.enabled", true) .put("xpack.security.http.ssl.supported_protocols", "TLSv1.2") .build(); sslService = new SSLService(settings, new Environment(settings)); @@ -123,7 +132,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testDisablesCompressionByDefaultForSsl() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); + .put("xpack.security.http.ssl.enabled", true).build(); Settings.Builder pluginSettingsBuilder = Settings.builder(); SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); @@ -132,7 +141,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testLeavesCompressionOnIfNotSsl() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false).build(); + .put("xpack.security.http.ssl.enabled", false).build(); Settings.Builder pluginSettingsBuilder = Settings.builder(); SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); assertThat(pluginSettingsBuilder.build().isEmpty(), is(true)); @@ -140,7 +149,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testDoesNotChangeExplicitlySetCompression() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) + .put("xpack.security.http.ssl.enabled", true) .put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true) .build(); @@ -151,10 +160,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put("xpack.security.http.ssl.enabled", true) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -167,9 +176,9 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase { public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("xpack.security.ssl.truststore.password", "testnode") + .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) .build(); env = new Environment(settings); 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 81e4de857df..b3286ecad3e 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,8 +11,9 @@ 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.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.XPackSettings; +import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.netty3.Netty3MockUtil; @@ -20,6 +21,7 @@ import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.ssl.SslHandler; import org.junit.Before; +import javax.net.ssl.SSLEngine; import java.nio.file.Path; import java.util.Locale; @@ -38,37 +40,38 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void createSSLService() throws Exception { Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("path.home", createTempDir()) + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") .build(); - env = new Environment(Settings.builder().put("path.home", createTempDir()).build()); + env = new Environment(settings); sslService = new SSLService(settings, env); } public void testThatSSLCanBeDisabledByProfile() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", - Settings.builder().put("xpack.security.ssl", false).build()); + Settings.builder().put("xpack.security.ssl.enabled", false).build()); assertThat(factory.getPipeline().get(SslHandler.class), nullValue()); } public void testThatSSLCanBeEnabledByProfile() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), false).build(); + Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", - Settings.builder().put("xpack.security.ssl", true).build()); + Settings.builder().put("xpack.security.ssl.enabled", true).build()); assertThat(factory.getPipeline().get(SslHandler.class), notNullValue()); } public void testThatProfileTakesDefaultSSLSetting() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); @@ -78,7 +81,7 @@ public class SecurityNetty3TransportTests extends ESTestCase { } public void testDefaultClientAuth() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build(); SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); @@ -89,10 +92,13 @@ public class SecurityNetty3TransportTests extends ESTestCase { } public void testRequiredClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true"); + String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.client_authentication", value) + .build(); + 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)); @@ -103,10 +109,12 @@ public class SecurityNetty3TransportTests extends ESTestCase { } public void testNoClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)); + String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.client_authentication", value).build(); + 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)); @@ -119,8 +127,10 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void testOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.client_authentication", value).build(); + 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)); @@ -131,50 +141,65 @@ public class SecurityNetty3TransportTests extends ESTestCase { } public void testProfileRequiredClientAuth() throws Exception { - 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(); + String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + 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)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", - Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING, value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false)); } public void testProfileNoClientAuth() throws Exception { - 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(); + String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + 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)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", - Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false)); } public void testProfileOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); - Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + 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)); Netty3MockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", - Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); 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", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -189,10 +214,10 @@ public class SecurityNetty3TransportTests extends ESTestCase { public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -202,4 +227,36 @@ public class SecurityNetty3TransportTests extends ESTestCase { mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class)); assertNotNull(transport.configureServerChannelPipelineFactory(randomAsciiOfLength(6), Settings.EMPTY)); } + + public void testTransportSSLOverridesGlobalSSL() throws Exception { + final boolean useGlobalKeystoreWithoutKey = randomBoolean(); + Settings.Builder builder = Settings.builder() + .put("xpack.security.transport.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.transport.ssl.keystore.password", "testnode") + .put("xpack.security.transport.ssl.client_authentication", "none") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true) + .put("path.home", createTempDir()); + if (useGlobalKeystoreWithoutKey) { + builder.put("xpack.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) + .put("xpack.ssl.keystore.password", "truststore-testnode-only"); + } + Settings settings = builder.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)); + Netty3MockUtil.setOpenChannelsHandlerToMock(transport); + ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("default", Settings.EMPTY); + final SSLEngine engine = factory.getPipeline().get(SslHandler.class).getEngine(); + assertFalse(engine.getNeedClientAuth()); + assertFalse(engine.getWantClientAuth()); + + // get the global and verify that it is different in that it requires client auth + final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); + assertTrue(globalEngine.getNeedClientAuth()); + assertFalse(globalEngine.getWantClientAuth()); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SslHostnameVerificationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SslHostnameVerificationTests.java index a5fcfbfae36..ffa3c34b33b 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SslHostnameVerificationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/netty3/SslHostnameVerificationTests.java @@ -37,7 +37,7 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase { Settings settings = super.nodeSettings(nodeOrdinal); Settings.Builder settingsBuilder = Settings.builder(); for (Entry entry : settings.getAsMap().entrySet()) { - if (entry.getKey().startsWith("xpack.security.ssl.") == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { settingsBuilder.put(entry.getKey(), entry.getValue()); } } @@ -54,12 +54,12 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase { throw new RuntimeException(e); } - return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) - .put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname") - .put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) - .put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname") - // disable hostname verification as this test uses non-localhost addresses - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false) + return settingsBuilder.put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) + .put("xpack.ssl.keystore.password", "testnode-no-subjaltname") + .put("xpack.ssl.truststore.path", keystore.toAbsolutePath()) + .put("xpack.ssl.truststore.password", "testnode-no-subjaltname") + // disable hostname verification as this test uses certs without a valid SAN or DNS in the CN + .put("xpack.ssl.verification_mode", "certificate") .build(); } @@ -72,19 +72,19 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase { Settings.Builder builder = Settings.builder(); for (Entry entry : settings.getAsMap().entrySet()) { String key = entry.getKey(); - if (key.startsWith(Security.setting("ssl.")) == false) { + if (key.startsWith("xpack.ssl.") == false) { builder.put(key, entry.getValue()); } } - builder.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false) - .put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client keystore - .put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname"); + builder.put("xpack.ssl.verification_mode", "certificate") + .put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client keystore + .put("xpack.ssl.keystore.password", "testnode-no-subjaltname"); if (randomBoolean()) { // randomly set the truststore, if not set the keystore should be used - builder.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) - .put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname"); + builder.put("xpack.ssl.truststore.path", keystore.toAbsolutePath()) + .put("xpack.ssl.truststore.password", "testnode-no-subjaltname"); } return builder.build(); } @@ -96,7 +96,7 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase { InetSocketAddress inetSocketAddress = ((InetSocketTransportAddress) transportAddress).address(); Settings settings = Settings.builder().put(transportClientSettings()) - .put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true) + .put("xpack.ssl.verification_mode", "full") .build(); try (TransportClient client = new XPackTransportClient(settings)) { 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 3b81dcf2d1c..1a1c1cda354 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,9 @@ 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.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.XPackSettings; +import org.elasticsearch.xpack.ssl.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.junit.Before; @@ -42,8 +43,8 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void createSSLService() throws Exception { Path testNodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testNodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", testNodeStore) + .put("xpack.ssl.keystore.password", "testnode") .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -51,7 +52,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { } public void testDefaultClientAuth() throws Exception { - Settings settings = Settings.builder().put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build(); + Settings settings = Settings.builder() + .put(env.settings()) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); + sslService = new SSLService(settings, env); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -64,8 +68,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) + .put("xpack.security.http.ssl.client_authentication", value).build(); + sslService = new SSLService(settings, env); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -76,10 +82,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { } public void testRequiredClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE"); + String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) + .put("xpack.security.http.ssl.client_authentication", value).build(); + sslService = new SSLService(settings, env); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -90,10 +98,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { } public void testNoClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.NO.name(), SSLClientAuth.NO.name().toLowerCase(Locale.ROOT), "false", "FALSE"); + String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT)); Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build(); + .put(env.settings()) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) + .put("xpack.security.http.ssl.client_authentication", value).build(); + sslService = new SSLService(settings, env); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -105,7 +115,9 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testCustomSSLConfiguration() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build(); + .put(env.settings()) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); + sslService = new SSLService(settings, env); SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class)); Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport); @@ -115,7 +127,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { settings = Settings.builder() .put(env.settings()) - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) .put("xpack.security.http.ssl.supported_protocols", "TLSv1.2") .build(); sslService = new SSLService(settings, new Environment(settings)); @@ -131,7 +143,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testDisablesCompressionByDefaultForSsl() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build(); + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); Settings.Builder pluginSettingsBuilder = Settings.builder(); SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); @@ -140,7 +152,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testLeavesCompressionOnIfNotSsl() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), false).build(); + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), false).build(); Settings.Builder pluginSettingsBuilder = Settings.builder(); SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings); assertThat(pluginSettingsBuilder.build().isEmpty(), is(true)); @@ -148,7 +160,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testDoesNotChangeExplicitlySetCompression() throws Exception { Settings settings = Settings.builder() - .put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) .put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true) .build(); @@ -159,10 +171,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -175,9 +187,9 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("xpack.security.ssl.truststore.password", "testnode") + .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) .build(); env = new Environment(settings); 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 bbdb87e180a..94a520b1512 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,10 +17,12 @@ 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.SSLService; -import org.elasticsearch.xpack.security.transport.SSLClientAuth; +import org.elasticsearch.xpack.XPackSettings; +import org.elasticsearch.xpack.ssl.SSLClientAuth; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.Before; +import javax.net.ssl.SSLEngine; import java.nio.file.Path; import java.util.Locale; @@ -39,8 +41,8 @@ public class SecurityNetty4TransportTests extends ESTestCase { public void createSSLService() throws Exception { Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -54,7 +56,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { private SecurityNetty4Transport createTransport(boolean sslEnabled, Settings additionalSettings) { final Settings settings = Settings.builder() - .put(SecurityNetty4Transport.SSL_SETTING.getKey(), sslEnabled) + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslEnabled) .put(additionalSettings) .build(); return new SecurityNetty4Transport( @@ -72,7 +74,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { SecurityNetty4Transport transport = createTransport(true); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", - Settings.builder().put("xpack.security.ssl", false).build()); + Settings.builder().put("xpack.security.ssl.enabled", false).build()); final EmbeddedChannel ch = new EmbeddedChannel(handler); assertThat(ch.pipeline().get(SslHandler.class), nullValue()); } @@ -81,7 +83,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { SecurityNetty4Transport transport = createTransport(false); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", - Settings.builder().put("xpack.security.ssl", true).build()); + Settings.builder().put("xpack.security.ssl.enabled", true).build()); final EmbeddedChannel ch = new EmbeddedChannel(handler); assertThat(ch.pipeline().get(SslHandler.class), notNullValue()); } @@ -104,9 +106,13 @@ public class SecurityNetty4TransportTests extends ESTestCase { } public void testRequiredClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true"); - SecurityNetty4Transport transport = - createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build()); + String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -115,9 +121,13 @@ public class SecurityNetty4TransportTests extends ESTestCase { } public void testNoClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)); - SecurityNetty4Transport transport = - createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build()); + String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -127,8 +137,12 @@ public class SecurityNetty4TransportTests extends ESTestCase { public void testOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); - SecurityNetty4Transport transport = - createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build()); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY); final EmbeddedChannel ch = new EmbeddedChannel(handler); @@ -137,22 +151,34 @@ public class SecurityNetty4TransportTests extends ESTestCase { } public void testProfileRequiredClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE"); - SecurityNetty4Transport transport = createTransport(true); + String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", - Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING, value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); final EmbeddedChannel ch = new EmbeddedChannel(handler); assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true)); assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false)); } public void testProfileNoClientAuth() throws Exception { - String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)); - SecurityNetty4Transport transport = createTransport(true); + String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT)); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); ChannelHandler handler = transport.getServerChannelInitializer("client", - Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); final EmbeddedChannel ch = new EmbeddedChannel(handler); assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false)); assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false)); @@ -160,10 +186,16 @@ public class SecurityNetty4TransportTests extends ESTestCase { public void testProfileOptionalClientAuth() throws Exception { String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT)); - SecurityNetty4Transport transport = createTransport(true); + Settings settings = Settings.builder() + .put(env.settings()) + .put("xpack.security.transport.ssl.enabled", true) + .put("transport.profiles.client.xpack.security.ssl.client_authentication", value) + .build(); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); Netty4MockUtil.setOpenChannelsHandlerToMock(transport); final ChannelHandler handler = transport.getServerChannelInitializer("client", - Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build()); + Settings.builder().put("xpack.security.ssl.client_authentication", value).build()); final EmbeddedChannel ch = new EmbeddedChannel(handler); assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false)); assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true)); @@ -171,10 +203,10 @@ public class SecurityNetty4TransportTests extends ESTestCase { public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -188,10 +220,10 @@ public class SecurityNetty4TransportTests extends ESTestCase { public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", + .put("xpack.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("xpack.ssl.truststore.password", "testnode") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -200,4 +232,35 @@ public class SecurityNetty4TransportTests extends ESTestCase { mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService); assertNotNull(transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY)); } + + public void testTransportSSLOverridesGlobalSSL() throws Exception { + final boolean useGlobalKeystoreWithoutKey = randomBoolean(); + Settings.Builder builder = Settings.builder() + .put("xpack.security.transport.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) + .put("xpack.security.transport.ssl.keystore.password", "testnode") + .put("xpack.security.transport.ssl.client_authentication", "none") + .put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true) + .put("path.home", createTempDir()); + if (useGlobalKeystoreWithoutKey) { + builder.put("xpack.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) + .put("xpack.ssl.keystore.password", "truststore-testnode-only"); + } + Settings settings = builder.build(); + env = new Environment(settings); + sslService = new SSLService(settings, env); + SecurityNetty4Transport transport = createTransport(true, settings); + Netty4MockUtil.setOpenChannelsHandlerToMock(transport); + final ChannelHandler handler = transport.getServerChannelInitializer("default", Settings.EMPTY); + final EmbeddedChannel ch = new EmbeddedChannel(handler); + final SSLEngine engine = ch.pipeline().get(SslHandler.class).engine(); + assertFalse(engine.getNeedClientAuth()); + assertFalse(engine.getWantClientAuth()); + + // get the global and verify that it is different in that it requires client auth + final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); + assertTrue(globalEngine.getNeedClientAuth()); + assertFalse(globalEngine.getWantClientAuth()); + } } 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 808f0d63eec..a6ad62ea776 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.SSLService; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.XPackTransportClient; @@ -48,7 +47,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase { protected Settings nodeSettings(int nodeOrdinal) { return Settings.builder().put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build(); + .put("xpack.security.http.ssl.enabled", true).build(); } @Override @@ -62,7 +61,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase { .put(transportClientSettings()) .put("node.name", "programmatic_transport_client") .put("cluster.name", internalCluster().getClusterName()) - .putArray("xpack.security.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}) + .putArray("xpack.ssl.cipher_suites", "TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA") .build())) { TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()); @@ -81,7 +80,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase { .put(transportClientSettings()) .put("node.name", "programmatic_transport_client") .put("cluster.name", internalCluster().getClusterName()) - .putArray("xpack.security.ssl.supported_protocols", new String[]{"SSLv3"}) + .putArray("xpack.ssl.supported_protocols", new String[]{"SSLv3"}) .build())) { TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java index 3f95dee6380..d787e356361 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java @@ -11,7 +11,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.xpack.security.Security; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; +import org.elasticsearch.xpack.ssl.SSLClientAuth; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.XPackTransportClient; @@ -70,15 +70,14 @@ public class SslMultiPortTests extends SecurityIntegTestCase { .put("transport.profiles.client.port", randomClientPortRange) // make sure this is "localhost", no matter if ipv4 or ipv6, but be consistent .put("transport.profiles.client.bind_host", "localhost") - .put("transport.profiles.client.xpack.security.truststore.path", store.toAbsolutePath()) // settings for client truststore - .put("transport.profiles.client.xpack.security.truststore.password", "testnode-client-profile") + .put("transport.profiles.client.xpack.security.ssl.truststore.path", store.toAbsolutePath()) + .put("transport.profiles.client.xpack.security.ssl.truststore.password", "testnode-client-profile") .put("transport.profiles.no_ssl.port", randomNonSslPortRange) .put("transport.profiles.no_ssl.bind_host", "localhost") - .put(randomFrom( - "transport.profiles.no_ssl.xpack.security.ssl.enabled", "transport.profiles.no_ssl.xpack.security.ssl"), "false") + .put("transport.profiles.no_ssl.xpack.security.ssl.enabled", "false") .put("transport.profiles.no_client_auth.port", randomNoClientAuthPortRange) .put("transport.profiles.no_client_auth.bind_host", "localhost") - .put("transport.profiles.no_client_auth.xpack.security.ssl.client.auth", false) + .put("transport.profiles.no_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.NONE) .build(); } @@ -89,10 +88,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { private TransportClient createTransportClient(Settings additionalSettings) { Settings clientSettings = transportClientSettings(); - if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) { + if (additionalSettings.getByPrefix("xpack.ssl.").isEmpty() == false) { Settings.Builder builder = Settings.builder(); for (Entry entry : clientSettings.getAsMap().entrySet()) { - if (entry.getKey().startsWith("xpack.security.ssl.") == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { builder.put(entry.getKey(), entry.getValue()); } } @@ -234,7 +233,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { public void testThatTransportClientCanConnectToNoSslProfile() throws Exception { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), false) + .put("xpack.security.transport.ssl.enabled", false) .put("cluster.name", internalCluster().getClusterName()) .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { @@ -307,10 +306,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.truststore.path", + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.ssl.truststore.password", "truststore-testnode-only") + .put("xpack.ssl.truststore.password", "truststore-testnode-only") .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), @@ -329,10 +328,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.truststore.path", + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.ssl.truststore.password", "truststore-testnode-only") + .put("xpack.ssl.truststore.password", "truststore-testnode-only") .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client"))); @@ -353,10 +352,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.truststore.path", + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.ssl.truststore.password", "truststore-testnode-only") + .put("xpack.ssl.truststore.password", "truststore-testnode-only") .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses())); @@ -376,10 +375,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.truststore.path", + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.ssl.truststore.password", "truststore-testnode-only") + .put("xpack.ssl.truststore.password", "truststore-testnode-only") .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl"))); @@ -399,7 +398,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses())); @@ -419,7 +418,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client"))); @@ -439,7 +438,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .build(); try (TransportClient transportClient = new XPackTransportClient(settings)) { transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), @@ -451,26 +450,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase { } } - /** - * Uses a transport client with the default JDK truststore; this truststore only trusts the known good public - * certificate authorities. This test connects to the no_ssl profile, which does not use SSL so the connection - * will not work - */ - public void testThatSSLTransportClientWithNoTruststoreCannotConnectToNoSslProfile() throws Exception { - Settings settings = Settings.builder() - .put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD) - .put("cluster.name", internalCluster().getClusterName()) - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .build(); - try (TransportClient transportClient = new XPackTransportClient(settings)) { - transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl"))); - assertGreenClusterState(transportClient); - fail("Expected NoNodeAvailableException"); - } catch (NoNodeAvailableException e) { - assertThat(e.getMessage(), containsString("None of the configured nodes are available: [{#transport#-")); - } - } - private static int getProfilePort(String profile) { TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddresses()); diff --git a/elasticsearch/x-pack/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks b/elasticsearch/x-pack/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks index 71d33bfacf25a3cec5acd7f73e7e2fbbc5e14dd5..f18b9288b10b82dd290fe5586130a90a045239ef 100644 GIT binary patch delta 65 zcmZ21G=oFw-`jt085kItfS3_XbCjeOm*nNAqyh!P=E>f>x>=X?5wl2}@Pc`J?-eq= R+2@>j;L6R8gl}uk0RXf)8Dsze delta 1365 zcmV-b1*-a(2%{2z{_Xzl00002000010000100?wtb98QRWMu#V0Z;plE*|Wp3C)TsTgAV&GfI<$oo) zZsYB;O!R;Rn@?Pc_QAo>&zX^jMiTHf-*9X%#k2XCN<}v`$xy(3*o#MG2r=^BpIvB1 zw$~Vk1#Y8%{Vdenw2y3aCdP-le&pW*_1JJ28QRRWXoAgV%Wot3pzVS-k{jF^hCOQk z)0lJy3&1=Ev;+2%F(o6rM}~C8e!o0`^Hq{o4smy#3{T3V){8 z{LxKY(+(Ge(G&=K4RF~N{8`Moo$I0$L!r-E7Ehah#2B=sK`?Y0JN@r0R%uwtgO)OS z#yW0u9I4R!X6-U2Y_ND&rI#X9Is1wU;50X_VftG~Q3&s$Ito&A6{Q)VOeH1YvX@04 zqBVE70`3S>Uv-&#e{7KYFkY-Ie0V13B{)qV+oIA+8Uvpwh;Sp$DPPz>Elsxs}f_Zn}CqY>!$^S$)gP_XtcXC)GAJbwJ-}wfLd$J_RYs6RE9$bZD>XOz2 z>D_g`09U0cK9ZxMD~s=6)Lhe?A@*w4C{(|H`<3!gHfZXVhW%!18#b7sm2Nd`F&Udc zv~1iib9%h~g17LStbX#By=QFAhgN79K!FNzyJ&gxB+vRS37oLG+cR7aMBbh7A<-Ss z-(46a=E0&n%NhLRu26uQVwXqYo+(**6unOev!%uTo!kv`s%$!6iw-Q%4Ub*j;4#yG z6w!Lw%(X(OIO?I}qV8U6KUbN;?;Ku2Qv1PL{Y>O#SougegvZ1`A#S7d$_hKzsCWNX zuC{iRH>R9ysEp3etTD^YqUQ3svJg;?P>EjOt4I)RJxN*fSwLQ?V7on@dh{)vwM{;b zCcLU8VP6xZ`;Ac~LV7eNV%3nmsyF<9&4O5P>U8ejC%(5{!(Az4R*t-4>RuIQHr%Ux zdIX{3ZN-6Ar7DwdisOYN>@%Fq{wgQ>eyp&=+VSXn5@uN+;GYLTt7|XHFH)HcnJ_K{ z@e7E7lVfS-Of~78uSPkqE*O2jN-S0|ED^lnlXf!r*j9=*lZ_8S4Je8QU!OyN%iDDO zwK!wo=Rah?fXS$Ft`*KPd%L%=V&Ka z+1xfXqlQu%EuU5n-M2=3zs&6T59bqo$XmzV&@~|`j00058BH{xS XaA`j*u4flC9e!T1uoXmjHK+c~c!`nK diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/common/network/InetAddressHelper.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/common/network/InetAddressHelper.java similarity index 100% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/common/network/InetAddressHelper.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/common/network/InetAddressHelper.java diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 6faaf1aa7b5..9de4e85f5c0 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -89,6 +89,8 @@ import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.SecurityFeatureSet; import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; +import org.elasticsearch.xpack.ssl.SSLConfigurationReloader; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.support.clock.Clock; import org.elasticsearch.xpack.support.clock.SystemClock; import org.elasticsearch.xpack.watcher.Watcher; @@ -152,6 +154,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I protected final XPackExtensionsService extensionsService; protected XPackLicenseState licenseState; + protected SSLService sslService; protected Licensing licensing; protected Security security; protected Monitoring monitoring; @@ -163,9 +166,10 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I this.transportClientMode = transportClientMode(settings); this.env = transportClientMode ? null : new Environment(settings); this.licenseState = new XPackLicenseState(); + this.sslService = new SSLService(settings, env); this.licensing = new Licensing(settings); - this.security = new Security(settings, env, licenseState); + this.security = new Security(settings, env, licenseState, sslService); this.monitoring = new Monitoring(settings, env, licenseState); this.watcher = new Watcher(settings); this.graph = new Graph(settings); @@ -207,6 +211,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I ResourceWatcherService resourceWatcherService, ScriptService scriptService, SearchRequestParsers searchRequestParsers) { List components = new ArrayList<>(); + components.add(sslService); + final InternalClient internalClient = new InternalClient(settings, threadPool, client, security.getCryptoService()); components.add(internalClient); @@ -217,7 +223,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I components.addAll(security.createComponents(internalClient, threadPool, clusterService, resourceWatcherService, extensionsService.getExtensions())); - components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService)); + components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService, sslService)); // watcher http stuff Map httpAuthFactories = new HashMap<>(); @@ -226,12 +232,14 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories); HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry); components.add(httpTemplateParser); - final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, env); + final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, env, sslService); components.add(httpClient); components.addAll(createNotificationComponents(clusterService.getClusterSettings(), httpClient, httpTemplateParser, scriptService)); + // just create the reloader as it will pull all of the loaded ssl configurations and start watching them + new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService); return components; } @@ -288,7 +296,6 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I settings.addAll(MonitoringSettings.getSettings()); settings.addAll(watcher.getSettings()); settings.addAll(licensing.getSettings()); - settings.addAll(XPackSettings.getAllSettings()); // we add the `xpack.version` setting to all internal indices diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackSettings.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackSettings.java index 2dc2d09aea4..6727916ba5e 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackSettings.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackSettings.java @@ -6,13 +6,22 @@ package org.elasticsearch.xpack; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.function.Function; import org.elasticsearch.common.settings.Setting; +import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.xpack.ssl.SSLClientAuth; +import org.elasticsearch.xpack.ssl.VerificationMode; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; + +import static java.util.Collections.emptyList; /** * A container for xpack setting constants. @@ -41,6 +50,192 @@ public class XPackSettings { /** Setting for enabling or disabling document/field level security. Defaults to true. */ public static final Setting DLS_FLS_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".dls_fls", true); + /** Setting for enabling or disabling transport ssl. Defaults to false. */ + public static final Setting TRANSPORT_SSL_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".transport.ssl", false); + + /** Setting for enabling or disabling http ssl. Defaults to false. */ + public static final Setting HTTP_SSL_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".http.ssl", false); + + /* + * SSL settings. These are the settings that are specifically registered for SSL. Many are private as we do not explicitly use them + * but instead parse based on a prefix (eg *.ssl.*) + */ + public static final List DEFAULT_CIPHERS = + Arrays.asList("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA"); + public static final List DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1"); + public static final SSLClientAuth CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED; + public static final SSLClientAuth HTTP_CLIENT_AUTH_DEFAULT = SSLClientAuth.NONE; + public static final VerificationMode VERIFICATION_MODE_DEFAULT = VerificationMode.FULL; + + // global settings that apply to everything! + private static final Setting> CIPHERS_SETTING = Setting.listSetting("xpack.ssl.cipher_suites", DEFAULT_CIPHERS, + Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> SUPPORTED_PROTOCOLS_SETTING = Setting.listSetting("xpack.ssl.supported_protocols", + DEFAULT_SUPPORTED_PROTOCOLS, Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting CLIENT_AUTH_SETTING = new Setting<>("xpack.ssl.client_authentication", + CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse, Property.NodeScope, Property.Filtered); + private static final Setting VERIFICATION_MODE_SETTING = new Setting<>("xpack.ssl.verification_mode", + VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse, Property.NodeScope, Property.Filtered); + private static final Setting> KEYSTORE_PATH_SETTING = new Setting<>("xpack.ssl.keystore.path", + s -> System.getProperty("javax.net.ssl.keyStore"), Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> KEYSTORE_PASSWORD_SETTING = new Setting<>("xpack.ssl.keystore.password", + s -> System.getProperty("javax.net.ssl.keyStorePassword"), Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting KEYSTORE_ALGORITHM_SETTING = new Setting<>("xpack.ssl.keystore.algorithm", + s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), + Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> KEYSTORE_KEY_PASSWORD_SETTING = + new Setting<>("xpack.ssl.keystore.key_password", KEYSTORE_PASSWORD_SETTING, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting> TRUSTSTORE_PATH_SETTING = new Setting<>("xpack.ssl.truststore.path", + s -> System.getProperty("javax.net.ssl.trustStore"), Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> TRUSTSTORE_PASSWORD_SETTING = new Setting<>("xpack.ssl.truststore.password", + s -> System.getProperty("javax.net.ssl.trustStorePassword"), Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("xpack.ssl.truststore.algorithm", + s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()), + Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> KEY_PATH_SETTING = + new Setting<>("xpack.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> KEY_PASSWORD_SETTING = + new Setting<>("xpack.ssl.key_passphrase", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> CERT_SETTING = + new Setting<>("xpack.ssl.certificate", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> CA_PATHS_SETTING = Setting.listSetting("xpack.ssl.certificate_authorities", + Collections.emptyList(), s -> s, Property.NodeScope, Property.Filtered); + + // http specific settings + private static final Setting> HTTP_CIPHERS_SETTING = Setting.listSetting("xpack.security.http.ssl.cipher_suites", + DEFAULT_CIPHERS, Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_SUPPORTED_PROTOCOLS_SETTING = + Setting.listSetting("xpack.security.http.ssl.supported_protocols", emptyList(), Function.identity(), + Property.NodeScope, Property.Filtered); + private static final Setting HTTP_CLIENT_AUTH_SETTING = new Setting<>("xpack.security.http.ssl.client_authentication", + CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse, Property.NodeScope, Property.Filtered); + private static final Setting HTTP_VERIFICATION_MODE_SETTING = + new Setting<>("xpack.security.http.ssl.verification_mode", VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse, + Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_KEYSTORE_PATH_SETTING = new Setting<>("xpack.security.http.ssl.keystore.path", + (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_KEYSTORE_PASSWORD_SETTING = + new Setting<>("xpack.security.http.ssl.keystore.password", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting HTTP_KEYSTORE_ALGORITHM_SETTING = new Setting<>("xpack.security.http.ssl.keystore.algorithm", + "", Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_KEYSTORE_KEY_PASSWORD_SETTING = + new Setting<>("xpack.security.http.ssl.keystore.key_password", HTTP_KEYSTORE_PASSWORD_SETTING, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_TRUSTSTORE_PATH_SETTING = new Setting<>("xpack.security.http.ssl.truststore.path", + (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_TRUSTSTORE_PASSWORD_SETTING = + new Setting<>("xpack.security.http.ssl.truststore.password", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting HTTP_TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("xpack.security.http.ssl.truststore.algorithm", + "", Function.identity(), Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_KEY_PATH_SETTING = + new Setting<>("xpack.security.http.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_KEY_PASSWORD_SETTING = new Setting<>("xpack.security.http.ssl.key_passphrase", + (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_CERT_SETTING = new Setting<>("xpack.security.http.ssl.certificate", + (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> HTTP_CA_PATHS_SETTING = + Setting.listSetting("xpack.security.http.ssl.certificate_authorities", emptyList(), s -> s, + Property.NodeScope, Property.Filtered); + + // transport specific settings + private static final Setting> TRANSPORT_CIPHERS_SETTING = + Setting.listSetting("xpack.security.transport.ssl.cipher_suites", DEFAULT_CIPHERS, Function.identity(), + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_SUPPORTED_PROTOCOLS_SETTING = + Setting.listSetting("xpack.security.transport.ssl.supported_protocols", emptyList(), Function.identity(), + Property.NodeScope, Property.Filtered); + private static final Setting TRANSPORT_CLIENT_AUTH_SETTING = + new Setting<>("xpack.security.transport.ssl.client_authentication", CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse, + Property.NodeScope, Property.Filtered); + private static final Setting TRANSPORT_VERIFICATION_MODE_SETTING = + new Setting<>("xpack.security.transport.ssl.verification_mode", VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse, + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_KEYSTORE_PATH_SETTING = + new Setting<>("xpack.security.transport.ssl.keystore.path", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_KEYSTORE_PASSWORD_SETTING = + new Setting<>("xpack.security.transport.ssl.keystore.password", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting TRANSPORT_KEYSTORE_ALGORITHM_SETTING = + new Setting<>("xpack.security.transport.ssl.keystore.algorithm", "", Function.identity(), Property.NodeScope, + Property.Filtered); + private static final Setting> TRANSPORT_KEYSTORE_KEY_PASSWORD_SETTING = + new Setting<>("xpack.security.transport.ssl.keystore.key_password", TRANSPORT_KEYSTORE_PASSWORD_SETTING, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_TRUSTSTORE_PATH_SETTING = + new Setting<>("xpack.security.transport.ssl.truststore.path", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_TRUSTSTORE_PASSWORD_SETTING = + new Setting<>("xpack.security.transport.ssl.truststore.password", (String) null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + private static final Setting TRANSPORT_TRUSTSTORE_ALGORITHM_SETTING = + new Setting<>("xpack.security.transport.ssl.truststore.algorithm", "", Function.identity(), + Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_KEY_PATH_SETTING = + new Setting<>("xpack.security.transport.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_KEY_PASSWORD_SETTING = + new Setting<>("xpack.security.transport.ssl.key_passphrase", (String) null, Optional::ofNullable, Property.NodeScope, + Property.Filtered); + private static final Setting> TRANSPORT_CERT_SETTING = new Setting<>("xpack.security.transport.ssl.certificate", + (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + private static final Setting> TRANSPORT_CA_PATHS_SETTING = + Setting.listSetting("xpack.security.transport.ssl.certificate_authorities", emptyList(), s -> s, + Property.NodeScope, Property.Filtered); + /* End SSL settings */ + + static { + ALL_SETTINGS.add(CIPHERS_SETTING); + ALL_SETTINGS.add(SUPPORTED_PROTOCOLS_SETTING); + ALL_SETTINGS.add(KEYSTORE_PATH_SETTING); + ALL_SETTINGS.add(KEYSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(KEYSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(KEYSTORE_KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(KEY_PATH_SETTING); + ALL_SETTINGS.add(KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(CERT_SETTING); + ALL_SETTINGS.add(TRUSTSTORE_PATH_SETTING); + ALL_SETTINGS.add(TRUSTSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(TRUSTSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(CA_PATHS_SETTING); + ALL_SETTINGS.add(VERIFICATION_MODE_SETTING); + ALL_SETTINGS.add(CLIENT_AUTH_SETTING); + ALL_SETTINGS.add(HTTP_CIPHERS_SETTING); + ALL_SETTINGS.add(HTTP_SUPPORTED_PROTOCOLS_SETTING); + ALL_SETTINGS.add(HTTP_KEYSTORE_PATH_SETTING); + ALL_SETTINGS.add(HTTP_KEYSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(HTTP_KEYSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(HTTP_KEYSTORE_KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(HTTP_KEY_PATH_SETTING); + ALL_SETTINGS.add(HTTP_KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(HTTP_CERT_SETTING); + ALL_SETTINGS.add(HTTP_TRUSTSTORE_PATH_SETTING); + ALL_SETTINGS.add(HTTP_TRUSTSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(HTTP_TRUSTSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(HTTP_CA_PATHS_SETTING); + ALL_SETTINGS.add(HTTP_VERIFICATION_MODE_SETTING); + ALL_SETTINGS.add(HTTP_CLIENT_AUTH_SETTING); + ALL_SETTINGS.add(TRANSPORT_CIPHERS_SETTING); + ALL_SETTINGS.add(TRANSPORT_SUPPORTED_PROTOCOLS_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEYSTORE_PATH_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEYSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEYSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEYSTORE_KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEY_PATH_SETTING); + ALL_SETTINGS.add(TRANSPORT_KEY_PASSWORD_SETTING); + ALL_SETTINGS.add(TRANSPORT_CERT_SETTING); + ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_PATH_SETTING); + ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_PASSWORD_SETTING); + ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_ALGORITHM_SETTING); + ALL_SETTINGS.add(TRANSPORT_CA_PATHS_SETTING); + ALL_SETTINGS.add(TRANSPORT_VERIFICATION_MODE_SETTING); + ALL_SETTINGS.add(TRANSPORT_CLIENT_AUTH_SETTING); + } + /** * Create a Setting for the enabled state of features in xpack. * diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/http/HttpClient.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/http/HttpClient.java index 0f8a1290654..624eece797a 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/http/HttpClient.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/http/HttpClient.java @@ -5,25 +5,20 @@ */ package org.elasticsearch.xpack.common.http; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchTimeoutException; import org.elasticsearch.SpecialPermission; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.component.AbstractLifecycleComponent; +import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; import org.elasticsearch.xpack.common.http.auth.ApplicableHttpAuth; import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry; +import org.elasticsearch.xpack.ssl.SSLService; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -32,12 +27,8 @@ import java.net.SocketTimeoutException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; import java.security.AccessController; -import java.security.KeyStore; import java.security.PrivilegedAction; -import java.security.SecureRandom; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -45,30 +36,13 @@ import java.util.Map; /** * Client class to wrap http connections */ -public class HttpClient extends AbstractLifecycleComponent { +public class HttpClient extends AbstractComponent { static final String SETTINGS_SSL_PREFIX = "xpack.http.ssl."; static final String SETTINGS_PROXY_PREFIX = "xpack.http.proxy."; - static final String SETTINGS_SSL_SECURITY_PREFIX = "xpack.security.ssl."; - public static final String SETTINGS_SSL_PROTOCOL = SETTINGS_SSL_PREFIX + "protocol"; - static final String SETTINGS_SSL_SECURITY_PROTOCOL = SETTINGS_SSL_SECURITY_PREFIX + "protocol"; - public static final String SETTINGS_SSL_KEYSTORE = SETTINGS_SSL_PREFIX + "keystore.path"; - static final String SETTINGS_SSL_SECURITY_KEYSTORE = SETTINGS_SSL_SECURITY_PREFIX + "keystore.path"; - public static final String SETTINGS_SSL_KEYSTORE_PASSWORD = SETTINGS_SSL_PREFIX + "keystore.password"; - static final String SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "keystore.password"; - public static final String SETTINGS_SSL_KEYSTORE_KEY_PASSWORD = SETTINGS_SSL_PREFIX + "keystore.key_password"; - static final String SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "keystore.key_password"; - public static final String SETTINGS_SSL_KEYSTORE_ALGORITHM = SETTINGS_SSL_PREFIX + "keystore.algorithm"; - static final String SETTINGS_SSL_SECURITY_KEYSTORE_ALGORITHM = SETTINGS_SSL_SECURITY_PREFIX + "keystore.algorithm"; - public static final String SETTINGS_SSL_TRUSTSTORE = SETTINGS_SSL_PREFIX + "truststore.path"; - static final String SETTINGS_SSL_SECURITY_TRUSTSTORE = SETTINGS_SSL_SECURITY_PREFIX + "truststore.path"; - public static final String SETTINGS_SSL_TRUSTSTORE_PASSWORD = SETTINGS_SSL_PREFIX + "truststore.password"; - static final String SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "truststore.password"; - public static final String SETTINGS_SSL_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_PREFIX + "truststore.algorithm"; - static final String SETTINGS_SSL_SECURITY_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_SECURITY_PREFIX + "truststore.algorithm"; - public static final String SETTINGS_PROXY_HOST = SETTINGS_PROXY_PREFIX + "host"; - public static final String SETTINGS_PROXY_PORT = SETTINGS_PROXY_PREFIX + "port"; + static final String SETTINGS_PROXY_HOST = SETTINGS_PROXY_PREFIX + "host"; + static final String SETTINGS_PROXY_PORT = SETTINGS_PROXY_PREFIX + "port"; private final HttpAuthRegistry httpAuthRegistry; private final Environment env; @@ -78,16 +52,12 @@ public class HttpClient extends AbstractLifecycleComponent { private SSLSocketFactory sslSocketFactory; private HttpProxy proxy = HttpProxy.NO_PROXY; - public HttpClient(Settings settings, HttpAuthRegistry httpAuthRegistry, Environment env) { + public HttpClient(Settings settings, HttpAuthRegistry httpAuthRegistry, Environment env, SSLService sslService) { super(settings); this.httpAuthRegistry = httpAuthRegistry; this.env = env; defaultConnectionTimeout = settings.getAsTime("xpack.http.default_connection_timeout", TimeValue.timeValueSeconds(10)); defaultReadTimeout = settings.getAsTime("xpack.http.default_read_timeout", TimeValue.timeValueSeconds(10)); - } - - @Override - protected void doStart() throws ElasticsearchException { Integer proxyPort = settings.getAsInt(SETTINGS_PROXY_PORT, null); String proxyHost = settings.get(SETTINGS_PROXY_HOST, null); if (proxyPort != null && Strings.hasText(proxyHost)) { @@ -99,22 +69,7 @@ public class HttpClient extends AbstractLifecycleComponent { SETTINGS_PROXY_PORT); } } - - if (!settings.getByPrefix(SETTINGS_SSL_PREFIX).getAsMap().isEmpty() || - !settings.getByPrefix(SETTINGS_SSL_SECURITY_PREFIX).getAsMap().isEmpty()) { - sslSocketFactory = createSSLSocketFactory(settings); - } else { - logger.trace("no ssl context configured"); - sslSocketFactory = null; - } - } - - @Override - protected void doStop() throws ElasticsearchException { - } - - @Override - protected void doClose() throws ElasticsearchException { + sslSocketFactory = sslService.sslSocketFactory(settings.getByPrefix(SETTINGS_SSL_PREFIX)); } public HttpResponse execute(HttpRequest request) throws IOException { @@ -153,7 +108,7 @@ public class HttpClient extends AbstractLifecycleComponent { HttpProxy proxyToUse = request.proxy != null ? request.proxy : proxy; HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(proxyToUse.proxy()); - if (urlConnection instanceof HttpsURLConnection && sslSocketFactory != null) { + if (urlConnection instanceof HttpsURLConnection) { final HttpsURLConnection httpsConn = (HttpsURLConnection) urlConnection; final SSLSocketFactory factory = sslSocketFactory; SecurityManager sm = System.getSecurityManager(); @@ -224,107 +179,8 @@ public class HttpClient extends AbstractLifecycleComponent { return new HttpResponse(statusCode, body, responseHeaders); } - /** SSL Initialization **/ - private SSLSocketFactory createSSLSocketFactory(Settings settings) { - try { - String sslContextProtocol = settings.get(SETTINGS_SSL_PROTOCOL, settings.get(SETTINGS_SSL_SECURITY_PROTOCOL, "TLS")); - String keyStore = settings.get(SETTINGS_SSL_KEYSTORE, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE, - System.getProperty("javax.net.ssl.keyStore"))); - String keyStorePassword = settings.get(SETTINGS_SSL_KEYSTORE_PASSWORD, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD, - System.getProperty("javax.net.ssl.keyStorePassword"))); - String keyPassword = settings.get(SETTINGS_SSL_KEYSTORE_KEY_PASSWORD, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD, - keyStorePassword)); - String keyStoreAlgorithm = settings.get(SETTINGS_SSL_KEYSTORE_ALGORITHM, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_ALGORITHM, - System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()))); - String trustStore = settings.get(SETTINGS_SSL_TRUSTSTORE, settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE, - System.getProperty("javax.net.ssl.trustStore"))); - String trustStorePassword = settings.get(SETTINGS_SSL_TRUSTSTORE_PASSWORD, - settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD, System.getProperty("javax.net.ssl.trustStorePassword"))); - String trustStoreAlgorithm = settings.get(SETTINGS_SSL_TRUSTSTORE_ALGORITHM, - settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE_ALGORITHM, - System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()))); - - if (keyStore != null) { - if (trustStore == null) { - logger.debug("keystore defined with no truststore defined, using keystore as truststore"); - trustStore = keyStore; - trustStorePassword = keyStorePassword; - trustStoreAlgorithm = keyStoreAlgorithm; - } - } else if (trustStore == null) { - logger.debug("no truststore defined, using system default"); - } - - if (trustStoreAlgorithm == null) { - trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - } - logger.debug("using protocol [{}], keyStore [{}], keyStoreAlgorithm [{}], trustStore [{}] and trustAlgorithm [{}]", - sslContextProtocol, keyStore, keyStoreAlgorithm, trustStore, trustStoreAlgorithm); - - SSLContext sslContext = SSLContext.getInstance(sslContextProtocol); - KeyManager[] keyManagers = keyManagers(env, keyStore, keyStorePassword, keyStoreAlgorithm, keyPassword); - TrustManager[] trustManagers = trustManagers(env, trustStore, trustStorePassword, trustStoreAlgorithm); - sslContext.init(keyManagers, trustManagers, new SecureRandom()); - return sslContext.getSocketFactory(); - } catch (Exception e) { - throw new RuntimeException("http client failed to initialize the SSLContext", e); - } - } - + // TODO: we shouldn't expose this just for tests public SSLSocketFactory getSslSocketFactory() { return sslSocketFactory; } - - private static KeyManager[] keyManagers(Environment env, String keyStore, String keyStorePassword, String keyStoreAlgorithm, - String keyPassword) { - if (keyStore == null) { - return null; - } - Path path = env.configFile().resolve(keyStore); - if (Files.notExists(path)) { - return null; - } - - try { - // Load KeyStore - KeyStore ks = readKeystore(path, keyStorePassword); - - // Initialize KeyManagerFactory - KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm); - kmf.init(ks, keyPassword.toCharArray()); - return kmf.getKeyManagers(); - } catch (Exception e) { - throw new RuntimeException("http client failed to initialize a KeyManagerFactory", e); - } - } - - private static TrustManager[] trustManagers(Environment env, String trustStore, String trustStorePassword, String trustStoreAlgorithm) { - try { - // Load TrustStore - KeyStore ks = null; - if (trustStore != null) { - Path trustStorePath = env.configFile().resolve(trustStore); - if (Files.exists(trustStorePath)) { - ks = readKeystore(trustStorePath, trustStorePassword); - } - } - - // Initialize a trust manager factory with the trusted store - TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm); - trustFactory.init(ks); - return trustFactory.getTrustManagers(); - } catch (Exception e) { - throw new RuntimeException("http client failed to initialize a TrustManagerFactory", e); - } - } - - private static KeyStore readKeystore(Path path, String password) throws Exception { - try (InputStream in = Files.newInputStream(path)) { - // Load TrustStore - KeyStore ks = KeyStore.getInstance("jks"); - assert password != null; - ks.load(in, password.toCharArray()); - return ks; - } - } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertUtils.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java similarity index 72% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertUtils.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java index ab0817079d7..f2afc01f25d 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertUtils.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; @@ -30,7 +30,6 @@ import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.SuppressForbidden; @@ -71,13 +70,21 @@ import java.util.Locale; import java.util.Set; import java.util.function.Supplier; -class CertUtils { +/** + * Utility methods that deal with {@link Certificate}, {@link KeyStore}, {@link X509ExtendedTrustManager}, {@link X509ExtendedKeyManager} + * and other certificate related objects. + */ +public class CertUtils { private static final int SERIAL_BIT_LENGTH = 20 * 8; static final BouncyCastleProvider BC_PROV = new BouncyCastleProvider(); private CertUtils() {} + /** + * Resolves a path with or without an {@link Environment} as we may be running in a transport client where we do not have access to + * the environment + */ @SuppressForbidden(reason = "we don't have the environment to resolve files from when running in a transport client") static Path resolvePath(String path, @Nullable Environment environment) { if (environment != null) { @@ -86,15 +93,21 @@ class CertUtils { return PathUtils.get(Strings.cleanPath(path)); } - static X509ExtendedKeyManager keyManagers(Certificate[] certificateChain, PrivateKey privateKey, char[] password) throws Exception { + /** + * Returns a {@link X509ExtendedKeyManager} that is built from the provided private key and certificate chain + */ + static X509ExtendedKeyManager keyManager(Certificate[] certificateChain, PrivateKey privateKey, char[] password) throws Exception { KeyStore keyStore = KeyStore.getInstance("jks"); keyStore.load(null, null); // password must be non-null for keystore... keyStore.setKeyEntry("key", privateKey, password, certificateChain); - return keyManagers(keyStore, password, KeyManagerFactory.getDefaultAlgorithm()); + return keyManager(keyStore, password, KeyManagerFactory.getDefaultAlgorithm()); } - static X509ExtendedKeyManager keyManagers(KeyStore keyStore, char[] password, String algorithm) throws Exception { + /** + * Returns a {@link X509ExtendedKeyManager} that is built from the provided keystore + */ + static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm) throws Exception { KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(keyStore, password); KeyManager[] keyManagers = kmf.getKeyManagers(); @@ -106,7 +119,13 @@ class CertUtils { throw new IllegalStateException("failed to find a X509ExtendedKeyManager"); } - static X509ExtendedTrustManager trustManagers(Certificate[] certificates) throws Exception { + /** + * Creates a {@link X509ExtendedTrustManager} based on the provided certificates + * @param certificates the certificates to trust + * @return a trust manager that trusts the provided certificates + * @throws Exception if there is an error loading the certificates or trust manager + */ + public static X509ExtendedTrustManager trustManager(Certificate[] certificates) throws Exception { KeyStore store = KeyStore.getInstance("jks"); store.load(null, null); int counter = 0; @@ -114,23 +133,33 @@ class CertUtils { store.setCertificateEntry("cert" + counter, certificate); counter++; } - return trustManagers(store, TrustManagerFactory.getDefaultAlgorithm()); + return trustManager(store, TrustManagerFactory.getDefaultAlgorithm()); } - static X509ExtendedTrustManager trustManagers(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm, - Environment env) throws Exception { + /** + * Loads the truststore and creates a {@link X509ExtendedTrustManager} + * @param trustStorePath the path to the truststore + * @param trustStorePassword the password to the truststore + * @param trustStoreAlgorithm the algorithm to use for the truststore + * @param env the environment to use for file resolution. May be {@code null} + * @return a trust manager with the trust material from the store + * @throws Exception if an error occurs when loading the truststore or the trust manager + */ + public static X509ExtendedTrustManager trustManager(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm, + @Nullable Environment env) throws Exception { try (InputStream in = Files.newInputStream(resolvePath(trustStorePath, env))) { // TODO remove reliance on JKS since we can PKCS12 stores... KeyStore trustStore = KeyStore.getInstance("jks"); assert trustStorePassword != null; trustStore.load(in, trustStorePassword.toCharArray()); - return CertUtils.trustManagers(trustStore, trustStoreAlgorithm); - } catch (Exception e) { - throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); + return CertUtils.trustManager(trustStore, trustStoreAlgorithm); } } - static X509ExtendedTrustManager trustManagers(KeyStore keyStore, String algorithm) throws Exception { + /** + * Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore} + */ + static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm) throws Exception { TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); tmf.init(keyStore); TrustManager[] trustManagers = tmf.getTrustManagers(); @@ -142,7 +171,14 @@ class CertUtils { throw new IllegalStateException("failed to find a X509ExtendedTrustManager"); } - static Certificate[] readCertificates(List certPaths, Environment environment) throws Exception { + /** + * Reads the provided paths and parses them into {@link Certificate} objects + * @param certPaths the paths to the PEM encoded certificates + * @param environment the environment to resolve files against. May be {@code null} + * @return an array of {@link Certificate} objects + * @throws Exception if an error occurs reading a file or parsing a certificate + */ + public static Certificate[] readCertificates(List certPaths, @Nullable Environment environment) throws Exception { List certificates = new ArrayList<>(certPaths.size()); CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); for (String path : certPaths) { @@ -153,6 +189,9 @@ class CertUtils { return certificates.toArray(new Certificate[certificates.size()]); } + /** + * Reads the certificates from the provided reader + */ static void readCertificates(Reader reader, List certificates, CertificateFactory certFactory) throws Exception { try (PEMParser pemParser = new PEMParser(reader)) { @@ -178,6 +217,9 @@ class CertUtils { } } + /** + * Reads the private key from the reader and optionally uses the password supplier to retrieve a password if the key is encrypted + */ static PrivateKey readPrivateKey(Reader reader, Supplier passwordSupplier) throws Exception { try (PEMParser parser = new PEMParser(reader)) { Object parsed; @@ -219,17 +261,35 @@ class CertUtils { } } + /** + * Generates a CA certificate + */ static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair) throws Exception { return generateSignedCertificate(x500Principal, null, keyPair, null, null, true); } + /** + * Generates a signed certificate using the provided CA private key and information from the CA certificate + */ static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair, X509Certificate caCert, PrivateKey caPrivKey) throws Exception { return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false); } + /** + * Generates a signed certificate + * @param principal the principal of the certificate; commonly referred to as the distinguished name (DN) + * @param subjectAltNames the subject alternative names that should be added to the certificate as an X509v3 extension. May be + * {@code null} + * @param keyPair the key pair that will be associated with the certificate + * @param caCert the CA certificate. If {@code null}, this results in a self signed certificate + * @param caPrivKey the CA private key. If {@code null}, this results in a self signed certificate + * @param isCa whether or not the generated certificate is a CA + * @return a signed {@link X509Certificate} + * @throws Exception if an error occurs during the certificate creation + */ private static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair, - X509Certificate caCert, PrivateKey caPrivKey, boolean ca) throws Exception { + X509Certificate caCert, PrivateKey caPrivKey, boolean isCa) throws Exception { final DateTime notBefore = new DateTime(DateTimeZone.UTC); final DateTime notAfter = notBefore.plusYears(1); final BigInteger serial = CertUtils.getSerial(); @@ -259,7 +319,7 @@ class CertUtils { if (subjectAltNames != null) { builder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames); } - builder.addExtension(Extension.basicConstraints, ca, new BasicConstraints(ca)); + builder.addExtension(Extension.basicConstraints, isCa, new BasicConstraints(isCa)); PrivateKey signingKey = caPrivKey != null ? caPrivKey : keyPair.getPrivate(); ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey); @@ -267,6 +327,15 @@ class CertUtils { return new JcaX509CertificateConverter().getCertificate(certificateHolder); } + /** + * Generates a certificate signing request + * @param keyPair the key pair that will be associated by the certificate generated from the certificate signing request + * @param principal the principal of the certificate; commonly referred to as the distinguished name (DN) + * @param sanList the subject alternative names that should be added to the certificate as an X509v3 extension. May be +* {@code null} + * @return a certificate signing request + * @throws Exception if an error occurs generating or signing the CSR + */ static PKCS10CertificationRequest generateCSR(KeyPair keyPair, X500Principal principal, GeneralNames sanList) throws Exception { JcaPKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(principal, keyPair.getPublic()); if (sanList != null) { @@ -278,6 +347,9 @@ class CertUtils { return builder.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider(CertUtils.BC_PROV).build(keyPair.getPrivate())); } + /** + * Gets a random serial for a certificate that is generated from a {@link SecureRandom} + */ static BigInteger getSerial() { SecureRandom random = new SecureRandom(); BigInteger serial = new BigInteger(SERIAL_BIT_LENGTH, random); @@ -285,6 +357,9 @@ class CertUtils { return serial; } + /** + * Generates a RSA key pair with the provided key size (in bits) + */ static KeyPair generateKeyPair(int keysize) throws Exception { // generate a private key KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); @@ -292,6 +367,9 @@ class CertUtils { return keyPairGenerator.generateKeyPair(); } + /** + * Converts the {@link InetAddress} objects into a {@link GeneralNames} object that is used to represent subject alternative names. + */ static GeneralNames getSubjectAlternativeNames(boolean resolveName, Set addresses) throws Exception { Set generalNameList = new HashSet<>(); for (InetAddress address : addresses) { @@ -308,7 +386,7 @@ class CertUtils { } @SuppressForbidden(reason = "need to use getHostName to resolve DNS name and getHostAddress to ensure we resolved the name") - static void addSubjectAlternativeNames(boolean resolveName, InetAddress inetAddress, Set list) { + private static void addSubjectAlternativeNames(boolean resolveName, InetAddress inetAddress, Set list) { String hostaddress = inetAddress.getHostAddress(); String ip = NetworkAddress.format(inetAddress); list.add(new GeneralName(GeneralName.iPAddress, ip)); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertificateTool.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertificateTool.java similarity index 99% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertificateTool.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertificateTool.java index 43c19994bad..f8f20d32f01 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/CertificateTool.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/CertificateTool.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import joptsimple.OptionSet; import joptsimple.OptionSpec; diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/DefaultJDKTrustConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/DefaultJDKTrustConfig.java new file mode 100644 index 00000000000..29197ab8773 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/DefaultJDKTrustConfig.java @@ -0,0 +1,128 @@ +/* + * 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.ssl; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.env.Environment; + +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Path; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; + +/** + * This class represents a trust configuration that corresponds to the default trusted certificates of the JDK + */ +class DefaultJDKTrustConfig extends TrustConfig { + + static final DefaultJDKTrustConfig INSTANCE = new DefaultJDKTrustConfig(); + + private DefaultJDKTrustConfig() { + } + + @Override + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { + try { + return CertUtils.trustManager(null, TrustManagerFactory.getDefaultAlgorithm()); + } catch (Exception e) { + throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); + } + } + + @Override + List filesToMonitor(@Nullable Environment environment) { + return Collections.emptyList(); + } + + @Override + public String toString() { + return "JDK trusted certs"; + } + + @Override + public boolean equals(Object o) { + return o == this; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + /** + * Merges the default trust configuration with the provided {@link TrustConfig} + * @param trustConfig the trust configuration to merge with + * @return a {@link TrustConfig} that represents a combination of both trust configurations + */ + static TrustConfig merge(TrustConfig trustConfig) { + return new CombiningTrustConfig(trustConfig); + } + + /** + * A trust configuration that is a combination of a trust configuration with the default JDK trust configuration. This trust + * configuration returns a trust manager verifies certificates against both the default JDK trusted configurations and the specific + * {@link TrustConfig} provided. + */ + static class CombiningTrustConfig extends TrustConfig { + + private final TrustConfig trustConfig; + + private CombiningTrustConfig(TrustConfig trustConfig) { + this.trustConfig = trustConfig; + } + + @Override + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(environment); + X509ExtendedTrustManager defaultTrustManager = INSTANCE.createTrustManager(environment); + if (trustManager == null) { + return defaultTrustManager; + } + + X509Certificate[] firstIssuers = trustManager.getAcceptedIssuers(); + X509Certificate[] secondIssuers = defaultTrustManager.getAcceptedIssuers(); + X509Certificate[] acceptedIssuers = new X509Certificate[firstIssuers.length + secondIssuers.length]; + System.arraycopy(firstIssuers, 0, acceptedIssuers, 0, firstIssuers.length); + System.arraycopy(secondIssuers, 0, acceptedIssuers, firstIssuers.length, secondIssuers.length); + try { + return CertUtils.trustManager(acceptedIssuers); + } catch (Exception e) { + throw new ElasticsearchException("failed to create trust manager", e); + } + } + + @Override + List filesToMonitor(@Nullable Environment environment) { + return trustConfig.filesToMonitor(environment); + } + + @Override + public String toString() { + return "Combining Trust Config{first=[" + trustConfig.toString() + "], second=[" + INSTANCE.toString() + "]}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof CombiningTrustConfig)) { + return false; + } + + CombiningTrustConfig that = (CombiningTrustConfig) o; + return trustConfig.equals(that.trustConfig); + } + + @Override + public int hashCode() { + return trustConfig.hashCode(); + } + } +} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/KeyConfig.java similarity index 70% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/KeyConfig.java index baef56615e6..49657d6c66f 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/KeyConfig.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/KeyConfig.java @@ -3,43 +3,30 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.common.Nullable; import org.elasticsearch.env.Environment; -import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509ExtendedTrustManager; -import java.net.Socket; import java.nio.file.Path; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; abstract class KeyConfig extends TrustConfig { - KeyConfig(boolean includeSystem) { - super(includeSystem); - } - - static final KeyConfig NONE = new KeyConfig(false) { + static final KeyConfig NONE = new KeyConfig() { @Override X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { return null; } @Override - X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { return null; } - @Override - void validate() { - } - @Override List filesToMonitor(@Nullable Environment environment) { return Collections.emptyList(); @@ -49,6 +36,16 @@ abstract class KeyConfig extends TrustConfig { public String toString() { return "NONE"; } + + @Override + public boolean equals(Object o) { + return o == this; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } }; 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/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java similarity index 64% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java index bf92e63e8ac..7604f654b9b 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMKeyConfig.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java @@ -3,11 +3,10 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.Strings; import org.elasticsearch.env.Environment; import javax.net.ssl.X509ExtendedKeyManager; @@ -20,19 +19,29 @@ import java.security.PrivateKey; import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; +/** + * Implementation of a key configuration that is backed by a PEM encoded key file and one or more certificates + */ class PEMKeyConfig extends KeyConfig { - final String keyPath; - final String keyPassword; - final List certPaths; + private final String keyPath; + private final String keyPassword; + private final String certPath; - PEMKeyConfig(boolean includeSystem, String keyPath, String keyPassword, List certPaths) { - super(includeSystem); - this.keyPath = keyPath; + /** + * Creates a new key configuration backed by the key and certificate chain provided + * @param keyPath the path to the key file + * @param keyPassword the password for the key. May be {@code null} + * @param certChainPath the path to the file containing the certificate chain + */ + PEMKeyConfig(String keyPath, String keyPassword, String certChainPath) { + this.keyPath = Objects.requireNonNull(keyPath, "key file must be specified"); this.keyPassword = keyPassword; - this.certPaths = certPaths; + this.certPath = Objects.requireNonNull(certChainPath, "certificate must be specified"); } @Override @@ -41,8 +50,9 @@ class PEMKeyConfig extends KeyConfig { char[] password = keyPassword == null ? new char[0] : keyPassword.toCharArray(); try { PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment)); - Certificate[] certificateChain = CertUtils.readCertificates(certPaths, environment); - return CertUtils.keyManagers(certificateChain, privateKey, password); + Certificate[] certificateChain = CertUtils.readCertificates(Collections.singletonList(certPath), environment); + // password must be non-null for keystore... + return CertUtils.keyManager(certificateChain, privateKey, password); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e); } finally { @@ -52,7 +62,7 @@ class PEMKeyConfig extends KeyConfig { } } - PrivateKey readPrivateKey(Path keyPath) throws Exception { + private PrivateKey readPrivateKey(Path keyPath) throws Exception { char[] password = keyPassword == null ? null : keyPassword.toCharArray(); try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) { return CertUtils.readPrivateKey(reader, () -> password); @@ -64,31 +74,20 @@ class PEMKeyConfig extends KeyConfig { } @Override - X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { - Certificate[] certificates = CertUtils.readCertificates(certPaths, environment); - return CertUtils.trustManagers(certificates); + Certificate[] certificates = CertUtils.readCertificates(Collections.singletonList(certPath), environment); + return CertUtils.trustManager(certificates); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } } - @Override - void validate() { - if (keyPath == null) { - throw new IllegalArgumentException("no key file configured"); - } else if (certPaths == null || certPaths.isEmpty()) { - throw new IllegalArgumentException("no certificate provided"); - } - } - @Override List filesToMonitor(@Nullable Environment environment) { - List paths = new ArrayList<>(1 + certPaths.size()); + List paths = new ArrayList<>(2); paths.add(CertUtils.resolvePath(keyPath, environment)); - for (String certPath : certPaths) { - paths.add(CertUtils.resolvePath(certPath, environment)); - } + paths.add(CertUtils.resolvePath(certPath, environment)); return paths; } @@ -101,7 +100,7 @@ class PEMKeyConfig extends KeyConfig { if (keyPath != null ? !keyPath.equals(that.keyPath) : that.keyPath != null) return false; if (keyPassword != null ? !keyPassword.equals(that.keyPassword) : that.keyPassword != null) return false; - return certPaths != null ? certPaths.equals(that.certPaths) : that.certPaths == null; + return certPath != null ? certPath.equals(that.certPath) : that.certPath == null; } @@ -109,14 +108,14 @@ class PEMKeyConfig extends KeyConfig { public int hashCode() { int result = keyPath != null ? keyPath.hashCode() : 0; result = 31 * result + (keyPassword != null ? keyPassword.hashCode() : 0); - result = 31 * result + (certPaths != null ? certPaths.hashCode() : 0); + result = 31 * result + (certPath != null ? certPath.hashCode() : 0); return result; } @Override public String toString() { return "keyPath=[" + keyPath + - "], certPaths=[" + Strings.collectionToCommaDelimitedString(certPaths) + + "], certPaths=[" + certPath + "]"; } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMTrustConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/PEMTrustConfig.java similarity index 73% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMTrustConfig.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/PEMTrustConfig.java index 5e5f42ba45c..77c45763e68 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/PEMTrustConfig.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/PEMTrustConfig.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; @@ -15,33 +15,33 @@ import java.nio.file.Path; import java.security.cert.Certificate; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +/** + * Implementation of trust configuration that is backed by PEM encoded certificate files. + */ class PEMTrustConfig extends TrustConfig { - final List caPaths; + private final List caPaths; - PEMTrustConfig(boolean includeSystem, List caPaths) { - super(includeSystem); - this.caPaths = caPaths; + /** + * Create a new trust configuration that is built from the certificate files + * @param caPaths the paths to the certificate files to trust + */ + PEMTrustConfig(List caPaths) { + this.caPaths = Objects.requireNonNull(caPaths, "ca paths must be specified"); } @Override - X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { Certificate[] certificates = CertUtils.readCertificates(caPaths, environment); - return CertUtils.trustManagers(certificates); + return CertUtils.trustManager(certificates); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } } - @Override - void validate() { - if (caPaths == null) { - throw new IllegalArgumentException("no ca paths have been configured"); - } - } - @Override List filesToMonitor(@Nullable Environment environment) { List paths = new ArrayList<>(caPaths.size()); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLClientAuth.java similarity index 78% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLClientAuth.java index a08df4a2106..af290c93d96 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/SSLClientAuth.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLClientAuth.java @@ -3,14 +3,17 @@ * 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.transport; +package org.elasticsearch.xpack.ssl; import javax.net.ssl.SSLEngine; import java.util.Locale; +/** + * The client authentication mode that is used for SSL servers + */ public enum SSLClientAuth { - NO() { + NONE() { public boolean enabled() { return false; } @@ -40,25 +43,27 @@ public enum SSLClientAuth { } }; + /** + * @return true if client authentication is enabled + */ public abstract boolean enabled(); + /** + * Configure client authentication of the provided {@link SSLEngine} + */ public abstract void configure(SSLEngine engine); public static SSLClientAuth parse(String value) { assert value != null; switch (value.toLowerCase(Locale.ROOT)) { - case "no": - case "false": - return NO; - + case "none": + return NONE; case "optional": return OPTIONAL; - case "required": - case "true": return REQUIRED; default: - throw new IllegalArgumentException("could not resolve ssl client auth. unknown ssl client auth value [" + value + "]"); + throw new IllegalArgumentException("could not resolve ssl client auth. unknown value [" + value + "]"); } } } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java new file mode 100644 index 00000000000..db5c2f8ba40 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java @@ -0,0 +1,295 @@ +/* + * 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.ssl; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManagerFactory; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.settings.Setting; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; +import org.elasticsearch.xpack.XPackSettings; + +/** + * Represents the configuration for an SSLContext + */ +class SSLConfiguration { + + // These settings are never registered, but they exist so that we can parse the values defined under grouped settings. Also, some are + // implemented as optional settings, which provides a declarative manner for fallback as we typically fallback to values from a + // different configuration + private static final Setting> CIPHERS_SETTING = Setting.listSetting("cipher_suites", Collections.emptyList(), s -> s); + private static final Setting> SUPPORTED_PROTOCOLS_SETTING = + Setting.listSetting("supported_protocols", Collections.emptyList(), s -> s); + private static final Setting> KEYSTORE_PATH_SETTING = + new Setting<>("keystore.path", (String) null, Optional::ofNullable); + private static final Setting> KEYSTORE_PASSWORD_SETTING = + new Setting<>("keystore.password", (String) null, Optional::ofNullable); + private static final Setting KEYSTORE_ALGORITHM_SETTING = new Setting<>("keystore.algorithm", + s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), Function.identity()); + private static final Setting> KEYSTORE_KEY_PASSWORD_SETTING = + new Setting<>("keystore.key_password", KEYSTORE_PASSWORD_SETTING, Optional::ofNullable); + private static final Setting> TRUSTSTORE_PATH_SETTING = + new Setting<>("truststore.path", (String) null, Optional::ofNullable); + private static final Setting> TRUSTSTORE_PASSWORD_SETTING = + new Setting<>("truststore.password", (String) null, Optional::ofNullable); + private static final Setting TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("truststore.algorithm", + s -> System.getProperty("ssl.TrustManagerFactory.algorithm", + TrustManagerFactory.getDefaultAlgorithm()), Function.identity()); + private static final Setting> KEY_PATH_SETTING = + new Setting<>("key", (String) null, Optional::ofNullable); + private static final Setting> KEY_PASSWORD_SETTING = + new Setting<>("key_passphrase", (String) null, Optional::ofNullable); + private static final Setting> CERT_SETTING = + new Setting<>("certificate", (String) null, Optional::ofNullable); + private static final Setting> CA_PATHS_SETTING = + Setting.listSetting("certificate_authorities", Collections.emptyList(), s -> s); + private static final Setting> CLIENT_AUTH_SETTING = + new Setting<>("client_authentication", (String) null, s -> { + if (s == null) { + return Optional.ofNullable(null); + } else { + return Optional.of(SSLClientAuth.parse(s)); + } + }); + private static final Setting> VERIFICATION_MODE_SETTING = new Setting<>("verification_mode", (String) null, + s -> { + if (s == null) { + return Optional.ofNullable(null); + } else { + return Optional.of(VerificationMode.parse(s)); + } + }); + + private final KeyConfig keyConfig; + private final TrustConfig trustConfig; + private final List ciphers; + private final List supportedProtocols; + private final SSLClientAuth sslClientAuth; + private final VerificationMode verificationMode; + + /** + * Creates a new SSLConfiguration from the given settings. There is no fallback configuration when invoking this constructor so + * un-configured aspects will take on their default values. + * @param settings the SSL specific settings; only the settings under a *.ssl. prefix + */ + SSLConfiguration(Settings settings) { + this.keyConfig = createKeyConfig(settings, null); + this.trustConfig = createTrustConfig(settings, keyConfig, null); + this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, XPackSettings.DEFAULT_CIPHERS); + this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS); + this.sslClientAuth = CLIENT_AUTH_SETTING.get(settings).orElse(XPackSettings.CLIENT_AUTH_DEFAULT); + this.verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElse(XPackSettings.VERIFICATION_MODE_DEFAULT); + } + + /** + * Creates a new SSLConfiguration from the given settings and global/default SSLConfiguration. If the settings do not contain a value + * for a given aspect, the value from the global configuration will be used. + * @param settings the SSL specific settings; only the settings under a *.ssl. prefix + * @param globalSSLConfiguration the default configuration that is used as a fallback + */ + SSLConfiguration(Settings settings, SSLConfiguration globalSSLConfiguration) { + Objects.requireNonNull(globalSSLConfiguration); + this.keyConfig = createKeyConfig(settings, globalSSLConfiguration); + this.trustConfig = createTrustConfig(settings, keyConfig, globalSSLConfiguration); + this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, globalSSLConfiguration.cipherSuites()); + this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, globalSSLConfiguration.supportedProtocols()); + this.sslClientAuth = CLIENT_AUTH_SETTING.get(settings).orElse(globalSSLConfiguration.sslClientAuth()); + this.verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElse(globalSSLConfiguration.verificationMode()); + } + + /** + * The configuration for the key, if any, that will be used as part of this ssl configuration + */ + KeyConfig keyConfig() { + return keyConfig; + } + + /** + * The configuration of trust material that will be used as part of this ssl configuration + */ + TrustConfig trustConfig() { + return trustConfig; + } + + /** + * The cipher suites that will be used for this ssl configuration + */ + List cipherSuites() { + return ciphers; + } + + /** + * The protocols that are supported by this configuration + */ + List supportedProtocols() { + return supportedProtocols; + } + + /** + * The verification mode for this configuration; this mode controls certificate and hostname verification + */ + VerificationMode verificationMode() { + return verificationMode; + } + + /** + * The client auth configuration + */ + SSLClientAuth sslClientAuth() { + return sslClientAuth; + } + + /** + * Provides the list of paths to files that back this configuration + */ + List filesToMonitor(@Nullable Environment environment) { + if (keyConfig() == trustConfig()) { + return keyConfig().filesToMonitor(environment); + } + List paths = new ArrayList<>(keyConfig().filesToMonitor(environment)); + paths.addAll(trustConfig().filesToMonitor(environment)); + return paths; + } + + @Override + public String toString() { + return "SSLConfiguration{" + + "keyConfig=[" + keyConfig + + "], trustConfig=" + trustConfig + + "], cipherSuites=[" + ciphers + + "], supportedProtocols=[" + supportedProtocols + + "], sslClientAuth=[" + sslClientAuth + + "], verificationMode=[" + verificationMode + + "]}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SSLConfiguration)) return false; + + SSLConfiguration that = (SSLConfiguration) o; + + if (this.keyConfig() != null ? !this.keyConfig().equals(that.keyConfig()) : that.keyConfig() != null) { + return false; + } + if (this.trustConfig() != null ? !this.trustConfig().equals(that.trustConfig()) : that.trustConfig() != null) { + return false; + } + if (this.cipherSuites() != null ? !this.cipherSuites().equals(that.cipherSuites()) : that.cipherSuites() != null) { + return false; + } + if (!this.supportedProtocols().equals(that.supportedProtocols())) { + return false; + } + if (this.verificationMode() != that.verificationMode()) { + return false; + } + if (this.sslClientAuth() != that.sslClientAuth()) { + return false; + } + return this.supportedProtocols() != null ? + this.supportedProtocols().equals(that.supportedProtocols()) : that.supportedProtocols() == null; + } + + @Override + public int hashCode() { + int result = this.keyConfig() != null ? this.keyConfig().hashCode() : 0; + result = 31 * result + (this.trustConfig() != null ? this.trustConfig().hashCode() : 0); + result = 31 * result + (this.cipherSuites() != null ? this.cipherSuites().hashCode() : 0); + result = 31 * result + (this.supportedProtocols() != null ? this.supportedProtocols().hashCode() : 0); + result = 31 * result + this.verificationMode().hashCode(); + result = 31 * result + this.sslClientAuth().hashCode(); + return result; + } + + private static KeyConfig createKeyConfig(Settings settings, SSLConfiguration global) { + String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null); + String keyPath = KEY_PATH_SETTING.get(settings).orElse(null); + if (keyPath != null && keyStorePath != null) { + throw new IllegalArgumentException("you cannot specify a keystore and key file"); + } else if (keyStorePath == null && keyPath == null) { + if (global != null) { + return global.keyConfig(); + } else if (System.getProperty("javax.net.ssl.keyStore") != null) { + return new StoreKeyConfig(System.getProperty("javax.net.ssl.keyStore"), + System.getProperty("javax.net.ssl.keyStorePassword", ""), System.getProperty("javax.net.ssl.keyStorePassword", ""), + System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), + System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); + } + return KeyConfig.NONE; + } + + if (keyPath != null) { + String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null); + String certPath = CERT_SETTING.get(settings).orElse(null); + if (certPath == null) { + throw new IllegalArgumentException("you must specify the certificates to use with the key"); + } + return new PEMKeyConfig(keyPath, keyPassword, certPath); + } else { + String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null); + String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings); + String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword); + String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); + return new StoreKeyConfig(keyStorePath, keyStorePassword, keyStoreKeyPassword, keyStoreAlgorithm, trustStoreAlgorithm); + } + } + + private static TrustConfig createTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) { + String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null); + List caPaths = getListOrNull(CA_PATHS_SETTING, settings); + if (trustStorePath != null && caPaths != null) { + throw new IllegalArgumentException("you cannot specify a truststore and ca files"); + } + + VerificationMode verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElseGet(() -> { + if (global != null) { + return global.verificationMode(); + } + return XPackSettings.VERIFICATION_MODE_DEFAULT; + }); + if (verificationMode.isCertificateVerificationEnabled() == false) { + return TrustAllConfig.INSTANCE; + } else if (caPaths != null) { + return new PEMTrustConfig(caPaths); + } else if (trustStorePath != null) { + String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null); + String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings); + return new StoreTrustConfig(trustStorePath, trustStorePassword, trustStoreAlgorithm); + } else if (global == null && System.getProperty("javax.net.ssl.trustStore") != null) { + return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"), + System.getProperty("javax.net.ssl.trustStorePassword", ""), + System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); + } else if (global != null && keyConfig == global.keyConfig()) { + return global.trustConfig(); + } else if (keyConfig != KeyConfig.NONE) { + return DefaultJDKTrustConfig.merge(keyConfig); + } else { + return DefaultJDKTrustConfig.INSTANCE; + } + } + + private static List getListOrNull(Setting> listSetting, Settings settings) { + return getListOrDefault(listSetting, settings, null); + } + + private static List getListOrDefault(Setting> listSetting, Settings settings, List defaultValue) { + if (listSetting.exists(settings)) { + return listSetting.get(settings); + } + return defaultValue; + } +} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloader.java similarity index 97% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloader.java index 5c2179b4096..993bd794eeb 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloader.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloader.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; @@ -12,7 +12,7 @@ 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 org.elasticsearch.xpack.ssl.SSLService.SSLContextHolder; import javax.net.ssl.SSLContext; import java.io.IOException; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java similarity index 68% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java index 12eed7ff049..4890636af61 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/SSLService.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java @@ -3,22 +3,19 @@ * 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; +package org.elasticsearch.xpack.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 org.elasticsearch.xpack.XPackSettings; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -45,11 +42,6 @@ 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. @@ -60,13 +52,46 @@ public class SSLService extends AbstractComponent { private final SSLConfiguration globalSSLConfiguration; private final Environment env; + /** + * Create a new SSLService that parses the settings for the ssl contexts that need to be created, creates them, and then caches them + * for use later + */ public SSLService(Settings settings, Environment environment) { super(settings); this.env = environment; - this.globalSSLConfiguration = new Global(settings); + this.globalSSLConfiguration = new SSLConfiguration(settings.getByPrefix("xpack.ssl.")); this.sslContexts = loadSSLConfigurations(); } + /** + * Creates a new SSLService that supports dynamic creation of SSLContext instances. Instances created by this service will not be + * cached and will not be monitored for reloading. This dynamic server does have access to the cached and monitored instances that + * have been created during initialization + */ + public SSLService createDynamicSSLService() { + return new SSLService(settings, env) { + + @Override + Map loadSSLConfigurations() { + // we don't need to load anything... + return Collections.emptyMap(); + } + + /** + * Returns the existing {@link SSLContextHolder} for the configuration + * @throws IllegalArgumentException if not found + */ + SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) { + SSLContextHolder holder = SSLService.this.sslContexts.get(sslConfiguration); + if (holder == null) { + // normally we'd throw here but let's create a new one that is not cached and will not be monitored for changes! + holder = SSLService.this.createSslContext(sslConfiguration); + } + return holder; + } + }; + } + /** * 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 @@ -79,7 +104,7 @@ public class SSLService extends AbstractComponent { 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)); + supportedCiphers(socketFactory.getSupportedCipherSuites(), sslConfiguration.cipherSuites(), false)); } /** @@ -89,28 +114,32 @@ public class SSLService extends AbstractComponent { * 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 + * @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global configuration * @return {@link SSLEngine} */ - public SSLEngine createSSLEngine(Settings settings) { - return createSSLEngine(settings, null, -1); + public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings) { + return createSSLEngine(settings, fallbackSettings, 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 + * host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verification 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 fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global 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); + public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings, String host, int port) { + SSLConfiguration configuration = sslConfiguration(settings, fallbackSettings); SSLContext sslContext = sslContext(configuration); SSLEngine sslEngine = sslContext.createSSLEngine(host, port); - String[] ciphers = supportedCiphers(sslEngine.getSupportedCipherSuites(), configuration.ciphers(), false); + String[] ciphers = supportedCiphers(sslEngine.getSupportedCipherSuites(), configuration.cipherSuites(), false); try { sslEngine.setEnabledCipherSuites(ciphers); } catch (ElasticsearchException e) { @@ -125,16 +154,61 @@ public class SSLService extends AbstractComponent { } catch (IllegalArgumentException e) { throw new IllegalArgumentException("failed setting supported protocols " + Arrays.toString(supportedProtocols), e); } + + if (configuration.verificationMode().isHostnameVerificationEnabled() && host != null) { + // By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification + // we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against + // man in the middle attacks for all of our connections. + SSLParameters parameters = new SSLParameters(); + parameters.setEndpointIdentificationAlgorithm("HTTPS"); + sslEngine.setSSLParameters(parameters); + } + + // TODO configure using SSLParameters + configuration.sslClientAuth().configure(sslEngine); return sslEngine; } /** * Returns whether the provided settings results in a valid configuration that can be used for server connections + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix + * @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global configuration */ - public boolean isConfigurationValidForServerUsage(Settings settings) { - SSLConfiguration sslConfiguration = sslConfiguration(settings); + public boolean isConfigurationValidForServerUsage(Settings settings, Settings fallback) { + SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback); return sslConfiguration.keyConfig() != KeyConfig.NONE; } + /** + * Indicates whether client authentication is enabled for a particular configuration + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. The global configuration + * will be used for fallback + */ + public boolean isSSLClientAuthEnabled(Settings settings) { + return isSSLClientAuthEnabled(settings, Settings.EMPTY); + } + + /** + * Indicates whether client authentication is enabled for a particular configuration + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix + * @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global configuration + */ + public boolean isSSLClientAuthEnabled(Settings settings, Settings fallback) { + SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback); + return sslConfiguration.sslClientAuth().enabled(); + } + + /** + * Returns the {@link VerificationMode} that is specified in the settings (or the default) + * @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix + * @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global configuration + */ + public VerificationMode getVerificationMode(Settings settings, Settings fallback) { + SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback); + return sslConfiguration.verificationMode(); + } /** * Returns the {@link SSLContext} for the global configuration. Mainly used for testing @@ -171,7 +245,23 @@ public class SSLService extends AbstractComponent { if (settings.isEmpty()) { return globalSSLConfiguration; } - return new Custom(settings, globalSSLConfiguration); + return new SSLConfiguration(settings, globalSSLConfiguration); + } + + /** + * Returns the existing {@link SSLConfiguration} for the given settings and applies the provided fallback settings instead of the global + * configuration + * @param settings the settings for the ssl configuration + * @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY} + * results in a fallback to the global configuration + * @return the ssl configuration for the provided settings. If the settings are empty, the global configuration is returned + */ + SSLConfiguration sslConfiguration(Settings settings, Settings fallbackSettings) { + if (settings.isEmpty() && fallbackSettings.isEmpty()) { + return globalSSLConfiguration; + } + SSLConfiguration fallback = sslConfiguration(fallbackSettings); + return new SSLConfiguration(settings, fallback); } /** @@ -235,13 +325,11 @@ public class SSLService extends AbstractComponent { // Initialize sslContext try { - SSLContext sslContext = SSLContext.getInstance(sslConfiguration.protocol()); + SSLContext sslContext = SSLContext.getInstance(sslContextAlgorithm(sslConfiguration.supportedProtocols())); 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); + supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), sslConfiguration.cipherSuites(), true); return new SSLContextHolder(sslContext, trustManager, keyManager); } catch (NoSuchAlgorithmException | KeyManagementException e) { @@ -252,17 +340,29 @@ public class SSLService extends AbstractComponent { /** * Parses the settings to load all SSLConfiguration objects that will be used. */ - private Map loadSSLConfigurations() { + 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); + + final Settings transportSSLSettings = settings.getByPrefix("xpack.security.transport.ssl."); + List sslSettingsList = new ArrayList<>(); + sslSettingsList.add(transportSSLSettings); + sslSettingsList.add(getHttpTransportSSLSettings(settings)); + sslSettingsList.add(settings.getByPrefix("xpack.http.ssl.")); + sslSettingsList.addAll(getRealmsSSLSettings(settings)); + sslSettingsList.addAll(getMonitoringExporterSettings(settings)); + + for (Settings sslSettings : sslSettingsList) { + SSLConfiguration sslConfiguration = new SSLConfiguration(sslSettings, globalSSLConfiguration); + if (sslConfigurations.containsKey(sslConfiguration) == false) { + sslConfigurations.put(sslConfiguration, createSslContext(sslConfiguration)); + } + } + + // transport profiles are special since they fallback is to the transport settings which in turn falls back to global. + SSLConfiguration transportSSLConfiguration = new SSLConfiguration(transportSSLSettings, globalSSLConfiguration); + for (Settings profileSettings : getTransportProfileSSLSettings(settings)) { + SSLConfiguration sslConfiguration = new SSLConfiguration(profileSettings, transportSSLConfiguration); if (sslConfigurations.containsKey(sslConfiguration) == false) { sslConfigurations.put(sslConfiguration, createSslContext(sslConfiguration)); } @@ -270,11 +370,6 @@ public class SSLService extends AbstractComponent { 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 @@ -599,29 +694,9 @@ public class SSLService extends AbstractComponent { } } - 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); + Settings realmsSettings = settings.getByPrefix("xpack.security.authc.realms."); for (String name : realmsSettings.names()) { Settings realmSSLSettings = realmsSettings.getAsSettings(name).getByPrefix("ssl."); if (realmSSLSettings.isEmpty() == false) { @@ -631,23 +706,87 @@ public class SSLService extends AbstractComponent { return sslSettings; } - private static List getTransportSSLSettings(Settings settings) { + private static List getTransportProfileSSLSettings(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())); + Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl."); + if (profileSettings.isEmpty() == false) { + sslSettings.add(profileSettings); } } return sslSettings; } - private static List getHttpSSLSettings(Settings settings) { - if (SecurityNetty4HttpServerTransport.SSL_SETTING.get(settings)) { - return Collections.singletonList(settings.getByPrefix(setting("http.ssl."))); + public static Settings getHttpTransportSSLSettings(Settings settings) { + Settings httpSSLSettings = settings.getByPrefix("xpack.security.http.ssl."); + if (httpSSLSettings.isEmpty()) { + return httpSSLSettings; } - return Collections.emptyList(); + + Settings.Builder builder = Settings.builder().put(httpSSLSettings); + if (builder.get("client_authentication") == null) { + builder.put("client_authentication", XPackSettings.HTTP_CLIENT_AUTH_DEFAULT); + } + return builder.build(); + } + + private static List getMonitoringExporterSettings(Settings settings) { + List sslSettings = new ArrayList<>(); + Map exportersSettings = settings.getGroups("xpack.monitoring.exporters."); + for (Entry entry : exportersSettings.entrySet()) { + Settings exporterSSLSettings = entry.getValue().getByPrefix("ssl."); + if (exporterSSLSettings.isEmpty() == false) { + sslSettings.add(exporterSSLSettings); + } + } + return sslSettings; + } + + /** + * Maps the supported protocols to an appropriate ssl context algorithm. We make an attempt to use the "best" algorithm when + * possible. The names in this method are taken from the + * JCA Standard Algorithm Name + * Documentation for Java 8. + */ + private static String sslContextAlgorithm(List supportedProtocols) { + if (supportedProtocols.isEmpty()) { + return "TLSv1.2"; + } + + String algorithm = "SSL"; + for (String supportedProtocol : supportedProtocols) { + switch (supportedProtocol) { + case "TLSv1.2": + return "TLSv1.2"; + case "TLSv1.1": + if ("TLSv1.2".equals(algorithm) == false) { + algorithm = "TLSv1.1"; + } + break; + case "TLSv1": + switch (algorithm) { + case "TLSv1.2": + case "TLSv1.1": + break; + default: + algorithm = "TLSv1"; + } + break; + case "SSLv3": + switch (algorithm) { + case "SSLv2": + case "SSL": + algorithm = "SSLv3"; + } + break; + case "SSLv2": + case "SSLv2Hello": + break; + default: + throw new IllegalArgumentException("found unexpected value in supported protocols: " + supportedProtocol); + } + } + return algorithm; } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java similarity index 72% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java index b8e5c074c84..d0b5d4761ae 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreKeyConfig.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; @@ -17,7 +17,11 @@ import java.nio.file.Path; import java.security.KeyStore; import java.util.Collections; import java.util.List; +import java.util.Objects; +/** + * A key configuration that is backed by a {@link KeyStore} + */ class StoreKeyConfig extends KeyConfig { final String keyStorePath; @@ -26,11 +30,18 @@ class StoreKeyConfig extends KeyConfig { final String keyPassword; final String trustStoreAlgorithm; - StoreKeyConfig(boolean includeSystem, String keyStorePath, String keyStorePassword, String keyPassword, - String keyStoreAlgorithm, String trustStoreAlgorithm) { - super(includeSystem); - this.keyStorePath = keyStorePath; - this.keyStorePassword = keyStorePassword; + /** + * Creates a new configuration that can be used to load key and trust material from a {@link KeyStore} + * @param keyStorePath the path to the keystore file + * @param keyStorePassword the password for the keystore + * @param keyPassword the password for the private key in the keystore + * @param keyStoreAlgorithm the algorithm for the keystore + * @param trustStoreAlgorithm the algorithm to use when loading as a truststore + */ + StoreKeyConfig(String keyStorePath, String keyStorePassword, String keyPassword, String keyStoreAlgorithm, + String trustStoreAlgorithm) { + this.keyStorePath = Objects.requireNonNull(keyStorePath, "keystore path must be specified"); + this.keyStorePassword = Objects.requireNonNull(keyStorePassword, "keystore password must be specified"); this.keyPassword = keyPassword; this.keyStoreAlgorithm = keyStoreAlgorithm; this.trustStoreAlgorithm = trustStoreAlgorithm; @@ -39,34 +50,25 @@ class StoreKeyConfig extends KeyConfig { @Override X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) { - // TODO remove reliance on JKS since we can PKCS12 stores... + // TODO remove reliance on JKS since we can use PKCS12 stores in JDK8+... KeyStore ks = KeyStore.getInstance("jks"); assert keyStorePassword != null; ks.load(in, keyStorePassword.toCharArray()); - return CertUtils.keyManagers(ks, keyPassword.toCharArray(), keyStoreAlgorithm); + return CertUtils.keyManager(ks, keyPassword.toCharArray(), keyStoreAlgorithm); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e); } } @Override - X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) { + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { - return CertUtils.trustManagers(keyStorePath, keyStorePassword, trustStoreAlgorithm, environment); + return CertUtils.trustManager(keyStorePath, keyStorePassword, trustStoreAlgorithm, environment); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } } - @Override - void validate() { - if (keyStorePath == null) { - throw new IllegalArgumentException("keystore path must be specified"); - } else if (keyStorePassword == null) { - throw new IllegalArgumentException("no keystore password configured"); - } - } - @Override List filesToMonitor(@Nullable Environment environment) { return Collections.singletonList(CertUtils.resolvePath(keyStorePath, environment)); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java similarity index 70% rename from elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java rename to elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java index 1c7cb2571cc..d635e14e155 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/ssl/StoreTrustConfig.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; @@ -13,41 +13,39 @@ import javax.net.ssl.X509ExtendedTrustManager; import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.Objects; +/** + * Trust configuration that is backed by a {@link java.security.KeyStore} + */ class StoreTrustConfig extends TrustConfig { final String trustStorePath; final String trustStorePassword; final String trustStoreAlgorithm; - StoreTrustConfig(boolean includeSystem, String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) { - super(includeSystem); + /** + * Create a new configuration based on the provided parameters + * @param trustStorePath the path to the truststore + * @param trustStorePassword the password for the truststore + * @param trustStoreAlgorithm the algorithm to use for reading the truststore + */ + StoreTrustConfig(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) { this.trustStorePath = trustStorePath; - this.trustStorePassword = trustStorePassword; + this.trustStorePassword = trustStorePath != null ? + Objects.requireNonNull(trustStorePassword, "truststore password must be specified") : trustStorePassword; this.trustStoreAlgorithm = trustStoreAlgorithm; } @Override - X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) { - if (trustStorePath == null) { - return null; - } + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { - return CertUtils.trustManagers(trustStorePath, trustStorePassword, trustStoreAlgorithm, environment); + return CertUtils.trustManager(trustStorePath, trustStorePassword, trustStoreAlgorithm, environment); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } } - @Override - void validate() { - if (trustStorePath != null) { - if (trustStorePassword == null) { - throw new IllegalArgumentException("no truststore password configured"); - } - } - } - @Override List filesToMonitor(@Nullable Environment environment) { if (trustStorePath == null) { @@ -66,9 +64,7 @@ class StoreTrustConfig extends TrustConfig { if (trustStorePath != null ? !trustStorePath.equals(that.trustStorePath) : that.trustStorePath != null) return false; if (trustStorePassword != null ? !trustStorePassword.equals(that.trustStorePassword) : that.trustStorePassword != null) return false; - return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm == - null; - + return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm == null; } @Override diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustAllConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustAllConfig.java new file mode 100644 index 00000000000..c3032a30ebd --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustAllConfig.java @@ -0,0 +1,89 @@ +/* + * 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.ssl; + +import org.elasticsearch.common.Nullable; +import org.elasticsearch.env.Environment; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedTrustManager; +import java.net.Socket; +import java.nio.file.Path; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; + +/** + * A trust manager that trusts all certificates + */ +class TrustAllConfig extends TrustConfig { + + public static final TrustAllConfig INSTANCE = new TrustAllConfig(); + + /** + * The {@link X509ExtendedTrustManager} that will trust all certificates. All methods are implemented as a no-op and do not throw + * exceptions regardless of the certificate presented. + */ + private static final X509ExtendedTrustManager TRUST_MANAGER = new 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]; + } + }; + + private TrustAllConfig() { + } + + @Override + X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { + return TRUST_MANAGER; + } + + @Override + List filesToMonitor(@Nullable Environment environment) { + return Collections.emptyList(); + } + + @Override + public String toString() { + return "trust all"; + } + + @Override + public boolean equals(Object o) { + return o == this; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustConfig.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustConfig.java new file mode 100644 index 00000000000..0e0b6bb1c4e --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/TrustConfig.java @@ -0,0 +1,46 @@ +/* + * 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.ssl; + +import org.elasticsearch.common.Nullable; +import org.elasticsearch.env.Environment; + +import javax.net.ssl.X509ExtendedTrustManager; +import java.nio.file.Path; +import java.util.List; + +/** + * The configuration of trust material for SSL usage + */ +abstract class TrustConfig { + + /** + * Creates a {@link X509ExtendedTrustManager} based on the provided configuration + * @param environment the environment to resolve files against or null in the case of running in a transport client + */ + abstract X509ExtendedTrustManager createTrustManager(@Nullable Environment environment); + + /** + * Returns a list of files that should be monitored for changes + * @param environment the environment to resolve files against or null in the case of running in a transport client + */ + abstract List filesToMonitor(@Nullable Environment environment); + + /** + * {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation + */ + public abstract String toString(); + + /** + * {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation + */ + public abstract boolean equals(Object o); + + /** + * {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation + */ + public abstract int hashCode(); +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/VerificationMode.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/VerificationMode.java new file mode 100644 index 00000000000..116b1d96aac --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/ssl/VerificationMode.java @@ -0,0 +1,71 @@ +/* + * 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.ssl; + +import java.util.Locale; + +/** + * Represents the verification mode to be used for SSL connections. + */ +public enum VerificationMode { + NONE { + @Override + public boolean isHostnameVerificationEnabled() { + return false; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return false; + } + }, + CERTIFICATE { + @Override + public boolean isHostnameVerificationEnabled() { + return false; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return true; + } + }, + FULL { + @Override + public boolean isHostnameVerificationEnabled() { + return true; + } + + @Override + public boolean isCertificateVerificationEnabled() { + return true; + } + }; + + /** + * @return true if hostname verification is enabled + */ + public abstract boolean isHostnameVerificationEnabled(); + + /** + * @return true if certificate verification is enabled + */ + public abstract boolean isCertificateVerificationEnabled(); + + public static VerificationMode parse(String value) { + assert value != null; + switch (value.toLowerCase(Locale.ROOT)) { + case "none": + return NONE; + case "certificate": + return CERTIFICATE; + case "full": + return FULL; + default: + throw new IllegalArgumentException("could not resolve verification mode. unknown value [" + value + "]"); + } + } +} \ No newline at end of file diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java index d659ee93b3b..187cc2760e7 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java @@ -19,6 +19,7 @@ import org.elasticsearch.test.junit.annotations.Network; import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry; import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth; import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.After; import org.junit.Before; @@ -57,8 +58,7 @@ public class HttpClientTests extends ESTestCase { authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(null))); webServer = startWebServer(); webPort = webServer.getPort(); - httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment); - httpClient.start(); + httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment, new SSLService(environment.settings(), environment)); } @After @@ -162,24 +162,23 @@ public class HttpClientTests extends ESTestCase { Settings settings; if (randomBoolean()) { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_TRUSTSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_TRUSTSTORE_PASSWORD, "truststore-testnode-only") + .put("xpack.http.ssl.truststore.path", resource.toString()) + .put("xpack.http.ssl.truststore.password", "truststore-testnode-only") .build(); } else { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_SECURITY_TRUSTSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD, "truststore-testnode-only") + .put("xpack.ssl.truststore.path", resource.toString()) + .put("xpack.ssl.truststore.password", "truststore-testnode-only") .build(); } - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment)); // We can't use the client created above for the server since it is only a truststore - HttpClient httpClient2 = new HttpClient(Settings.builder() - .put(HttpClient.SETTINGS_SSL_KEYSTORE, getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks")) - .put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode") - .build(), authRegistry, environment); - httpClient2.start(); + Settings settings2 = Settings.builder() + .put("xpack.http.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks")) + .put("xpack.http.ssl.keystore.password", "testnode") + .build(); + HttpClient httpClient2 = new HttpClient(settings2, authRegistry, environment, new SSLService(settings2, environment)); webServer.useHttps(httpClient2.getSslSocketFactory(), false); webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body")); @@ -200,18 +199,17 @@ public class HttpClientTests extends ESTestCase { Settings settings; if (randomBoolean()) { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode") + .put("xpack.http.ssl.keystore.path", resource.toString()) + .put("xpack.http.ssl.keystore.password", "testnode") .build(); } else { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD, "testnode") + .put("xpack.ssl.keystore.path", resource.toString()) + .put("xpack.ssl.keystore.password", "testnode") .build(); } - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment)); webServer.useHttps(new ClientAuthRequiringSSLSocketFactory(httpClient.getSslSocketFactory()), false); webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body")); @@ -235,31 +233,30 @@ public class HttpClientTests extends ESTestCase { final boolean watcherSettings = randomBoolean(); if (watcherSettings) { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode") - .put(HttpClient.SETTINGS_SSL_KEYSTORE_KEY_PASSWORD, "testnode1") + .put("xpack.http.ssl.keystore.path", resource.toString()) + .put("xpack.http.ssl.keystore.password", "testnode") + .put("xpack.http.ssl.keystore.key_password", "testnode1") .build(); } else { settings = Settings.builder() - .put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD, "testnode") - .put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD, "testnode1") + .put("xpack.ssl.keystore.path", resource.toString()) + .put("xpack.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.key_password", "testnode1") .build(); } - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment)); assertThat(httpClient.getSslSocketFactory(), notNullValue()); Settings.Builder badSettings = Settings.builder().put(settings); if (watcherSettings) { - badSettings.remove(HttpClient.SETTINGS_SSL_KEYSTORE_KEY_PASSWORD); + badSettings.remove("xpack.http.ssl.keystore.key_password"); } else { - badSettings.remove(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD); + badSettings.remove("xpack.ssl.keystore.key_password"); } try { - new HttpClient(badSettings.build(), authRegistry, environment).start(); + new HttpClient(badSettings.build(), authRegistry, environment, new SSLService(badSettings.build(), environment)); fail("an exception should have been thrown since the key is not recoverable without the password"); } catch (Exception e) { UnrecoverableKeyException rootCause = (UnrecoverableKeyException) ExceptionsHelper.unwrap(e, UnrecoverableKeyException.class); @@ -294,9 +291,8 @@ public class HttpClientTests extends ESTestCase { @Network public void testHttpsWithoutTruststore() throws Exception { - HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment); - httpClient.start(); - assertThat(httpClient.getSslSocketFactory(), nullValue()); + HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment, new SSLService(Settings.EMPTY, environment)); + assertThat(httpClient.getSslSocketFactory(), notNullValue()); // Known server with a valid cert from a commercial CA HttpRequest.Builder request = HttpRequest.builder("www.elastic.co", 443).scheme(Scheme.HTTPS); @@ -309,13 +305,12 @@ public class HttpClientTests extends ESTestCase { @Network public void testHttpsWithoutTruststoreAndSSLIntegrationActive() throws Exception { // Add some settings with SSL prefix to force socket factory creation - String setting = (randomBoolean() ? HttpClient.SETTINGS_SSL_PREFIX : HttpClient.SETTINGS_SSL_SECURITY_PREFIX) + + String setting = (randomBoolean() ? HttpClient.SETTINGS_SSL_PREFIX : "xpack.ssl.") + "foo.bar"; Settings settings = Settings.builder() .put(setting, randomBoolean()) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(Settings.EMPTY, environment)); assertThat(httpClient.getSslSocketFactory(), notNullValue()); // Known server with a valid cert from a commercial CA @@ -336,8 +331,7 @@ public class HttpClientTests extends ESTestCase { .put(HttpClient.SETTINGS_PROXY_HOST, "localhost") .put(HttpClient.SETTINGS_PROXY_PORT, proxyServer.getPort()) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment)); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webPort) .method(HttpMethod.GET) @@ -365,8 +359,7 @@ public class HttpClientTests extends ESTestCase { .put(HttpClient.SETTINGS_PROXY_HOST, "localhost") .put(HttpClient.SETTINGS_PROXY_PORT, proxyServer.getPort() + 1) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment)); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webPort) .method(HttpMethod.GET) diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpConnectionTimeoutTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpConnectionTimeoutTests.java index a51336dbf21..119f03589ad 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpConnectionTimeoutTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpConnectionTimeoutTests.java @@ -11,10 +11,8 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; -import org.elasticsearch.xpack.common.http.HttpClient; -import org.elasticsearch.xpack.common.http.HttpMethod; -import org.elasticsearch.xpack.common.http.HttpRequest; import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry; +import org.elasticsearch.xpack.ssl.SSLService; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThan; @@ -29,8 +27,8 @@ public class HttpConnectionTimeoutTests extends ESTestCase { @Network public void testDefaultTimeout() throws Exception { Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment, + new SSLService(environment.settings(), environment)); HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345) .method(HttpMethod.POST) @@ -56,8 +54,7 @@ public class HttpConnectionTimeoutTests extends ESTestCase { Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); HttpClient httpClient = new HttpClient(Settings.builder() .put("xpack.http.default_connection_timeout", "5s").build() - , mock(HttpAuthRegistry.class), environment); - httpClient.start(); + , mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment)); HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345) .method(HttpMethod.POST) @@ -83,8 +80,7 @@ public class HttpConnectionTimeoutTests extends ESTestCase { Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); HttpClient httpClient = new HttpClient(Settings.builder() .put("xpack.http.default_connection_timeout", "10s").build() - , mock(HttpAuthRegistry.class), environment); - httpClient.start(); + , mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment)); HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345) .connectionTimeout(TimeValue.timeValueSeconds(5)) diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpReadTimeoutTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpReadTimeoutTests.java index 58caf5ad8e2..4ae9e7b491d 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpReadTimeoutTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/common/http/HttpReadTimeoutTests.java @@ -14,10 +14,8 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.common.http.HttpClient; -import org.elasticsearch.xpack.common.http.HttpMethod; -import org.elasticsearch.xpack.common.http.HttpRequest; import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry; +import org.elasticsearch.xpack.ssl.SSLService; import org.junit.After; import org.junit.Before; @@ -48,8 +46,8 @@ public class HttpReadTimeoutTests extends ESTestCase { public void testDefaultTimeout() throws Exception { Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment, + new SSLService(environment.settings(), environment)); // we're not going to enqueue an response... so the server will just hang @@ -76,8 +74,7 @@ public class HttpReadTimeoutTests extends ESTestCase { HttpClient httpClient = new HttpClient(Settings.builder() .put("xpack.http.default_read_timeout", "3s").build() - , mock(HttpAuthRegistry.class), environment); - httpClient.start(); + , mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment)); final String path = '/' + randomAsciiOfLength(5); final CountDownLatch latch = new CountDownLatch(1); @@ -109,8 +106,7 @@ public class HttpReadTimeoutTests extends ESTestCase { HttpClient httpClient = new HttpClient(Settings.builder() .put("xpack.http.default_read_timeout", "10s").build() - , mock(HttpAuthRegistry.class), environment); - httpClient.start(); + , mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment)); final String path = '/' + randomAsciiOfLength(5); final CountDownLatch latch = new CountDownLatch(1); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertUtilsTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertUtilsTests.java similarity index 99% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertUtilsTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertUtilsTests.java index 555d6a67fc2..c314da82d60 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertUtilsTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertUtilsTests.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertificateToolTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertificateToolTests.java similarity index 98% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertificateToolTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertificateToolTests.java index 4ae4aabc22e..4db0ae20d44 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/CertificateToolTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/CertificateToolTests.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.DEROctetString; @@ -24,9 +24,9 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.XPackPlugin; -import org.elasticsearch.xpack.security.ssl.CertificateTool.CAInfo; -import org.elasticsearch.xpack.security.ssl.CertificateTool.CertificateInformation; -import org.elasticsearch.xpack.security.ssl.CertificateTool.Name; +import org.elasticsearch.xpack.ssl.CertificateTool.CAInfo; +import org.elasticsearch.xpack.ssl.CertificateTool.CertificateInformation; +import org.elasticsearch.xpack.ssl.CertificateTool.Name; import javax.security.auth.x500.X500Principal; import java.io.Reader; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java similarity index 88% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java index edb3e7bfe60..d3bef0f39dc 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslClientAuthTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java @@ -3,7 +3,7 @@ * 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.transport.ssl; +package org.elasticsearch.xpack.ssl; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.message.BasicHeader; @@ -22,8 +22,6 @@ 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.transport.netty3.SecurityNetty3HttpServerTransport; -import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -42,16 +40,16 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; -public class SslClientAuthTests extends SecurityIntegTestCase { +public class SSLClientAuthTests extends SecurityIntegTestCase { @Override protected Settings nodeSettings(int nodeOrdinal) { return Settings.builder() .put(super.nodeSettings(nodeOrdinal)) // invert the require auth settings - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true) - .put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), true) - .put("transport.profiles.default.xpack.security.ssl.client.auth", false) + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.security.http.ssl.enabled", true) + .put("xpack.security.http.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("transport.profiles.default.xpack.security.ssl.client_authentication", SSLClientAuth.NONE) .put(NetworkModule.HTTP_ENABLED.getKey(), true) .build(); } @@ -92,9 +90,10 @@ public class SslClientAuthTests extends SecurityIntegTestCase { } Settings settings = Settings.builder() - .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) - .put("xpack.security.ssl.keystore.path", store) - .put("xpack.security.ssl.keystore.password", "testclient-client-profile") + .put("xpack.security.transport.ssl.enabled", true) + .put("xpack.ssl.client_authentication", SSLClientAuth.NONE) + .put("xpack.ssl.keystore.path", store) + .put("xpack.ssl.keystore.password", "testclient-client-profile") .put("cluster.name", internalCluster().getClusterName()) .put(Security.USER_SETTING.getKey(), transportClientUsername() + ":" + new String(transportClientPassword().internalChars())) diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java similarity index 94% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java index 8e5aa5c19be..bf72385993d 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationReloaderTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.apache.lucene.util.SetOnce; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; @@ -14,7 +14,6 @@ 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.SSLConfiguration.Global; import org.junit.After; import org.junit.Before; @@ -77,8 +76,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath); final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put("xpack.security.ssl.keystore.path", keystorePath) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", keystorePath) + .put("xpack.ssl.keystore.password", "testnode") .build(); final Environment env = randomBoolean() ? null : new Environment(settings); @@ -136,10 +135,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath); final Settings settings = Settings.builder() .put("path.home", createTempDir()) - .put("xpack.security.ssl.key.path", keyPath) - .put("xpack.security.ssl.key.password", "testnode") - .put("xpack.security.ssl.cert", certPath) - .putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString()) + .put("xpack.ssl.key", keyPath) + .put("xpack.ssl.key_passphrase", "testnode") + .put("xpack.ssl.certificate", certPath) + .putArray("xpack.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString()) .build(); final Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); @@ -201,8 +200,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path trustStorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath); Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", trustStorePath) - .put("xpack.security.ssl.truststore.password", "testnode") + .put("xpack.ssl.truststore.path", trustStorePath) + .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -247,9 +246,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path clientCertPath = tempDir.resolve("testclient.crt"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath); Settings settings = Settings.builder() - .putArray("xpack.security.ssl.ca", clientCertPath.toString()) + .putArray("xpack.ssl.certificate_authorities", clientCertPath.toString()) .put("path.home", createTempDir()) - .put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), false) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -291,8 +289,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path keystorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", keystorePath) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", keystorePath) + .put("xpack.ssl.keystore.password", "testnode") .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -329,10 +327,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), certPath); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath); Settings settings = Settings.builder() - .put("xpack.security.ssl.key.path", keyPath) - .put("xpack.security.ssl.key.password", "testnode") - .put("xpack.security.ssl.cert", certPath) - .putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString()) + .put("xpack.ssl.key", keyPath) + .put("xpack.ssl.key_passphrase", "testnode") + .put("xpack.ssl.certificate", certPath) + .putArray("xpack.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString()) .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -364,8 +362,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path trustStorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath); Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", trustStorePath) - .put("xpack.security.ssl.truststore.password", "testnode") + .put("xpack.ssl.truststore.path", trustStorePath) + .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -397,7 +395,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path clientCertPath = tempDir.resolve("testclient.crt"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath); Settings settings = Settings.builder() - .putArray("xpack.security.ssl.ca", clientCertPath.toString()) + .putArray("xpack.ssl.certificate_authorities", clientCertPath.toString()) .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java similarity index 50% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java index 6531d62f823..a07054e610c 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLConfigurationTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java @@ -3,22 +3,23 @@ * 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; +package org.elasticsearch.xpack.ssl; 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 org.elasticsearch.xpack.ssl.DefaultJDKTrustConfig.CombiningTrustConfig; import org.elasticsearch.test.ESTestCase; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; +import java.security.cert.X509Certificate; import java.util.Arrays; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.isIn; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; @@ -26,65 +27,51 @@ import static org.hamcrest.Matchers.sameInstance; public class SSLConfigurationTests extends ESTestCase { public void testThatSSLConfigurationHasCorrectDefaults() { - SSLConfiguration globalConfig = new Global(Settings.EMPTY); + SSLConfiguration globalConfig = new SSLConfiguration(Settings.EMPTY); assertThat(globalConfig.keyConfig(), sameInstance(KeyConfig.NONE)); assertThat(globalConfig.trustConfig(), is(not((globalConfig.keyConfig())))); - assertThat(globalConfig.trustConfig(), instanceOf(StoreTrustConfig.class)); - assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE))); - assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT))); - assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL))); + assertThat(globalConfig.trustConfig(), instanceOf(DefaultJDKTrustConfig.class)); - SSLConfiguration scopedConfig = new Custom(Settings.EMPTY, globalConfig); + SSLConfiguration scopedConfig = new SSLConfiguration(Settings.EMPTY, globalConfig); assertThat(scopedConfig.keyConfig(), sameInstance(globalConfig.keyConfig())); assertThat(scopedConfig.trustConfig(), sameInstance(globalConfig.trustConfig())); - assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE))); - assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT))); - assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL))); } public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() { + final String path = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString(); Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", "path") - .put("xpack.security.ssl.keystore.password", "password") + .put("keystore.path", path) + .put("keystore.password", "testnode") .build(); - Settings profileSettings = settings.getByPrefix("xpack.security.ssl."); // Pass settings in as component settings - SSLConfiguration globalSettings = new Global(settings); - SSLConfiguration scopedSettings = new Custom(profileSettings, globalSettings); + SSLConfiguration globalSettings = new SSLConfiguration(settings); + SSLConfiguration scopedSettings = new SSLConfiguration(settings, globalSettings); SSLConfiguration scopedEmptyGlobalSettings = - new Custom(profileSettings, new Global(Settings.EMPTY)); + new SSLConfiguration(settings, new SSLConfiguration(Settings.EMPTY)); for (SSLConfiguration sslConfiguration : Arrays.asList(globalSettings, scopedSettings, scopedEmptyGlobalSettings)) { assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); - assertThat(ksKeyInfo.keyStorePath, is(equalTo("path"))); - assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password"))); + assertThat(ksKeyInfo.keyStorePath, is(equalTo(path))); + assertThat(ksKeyInfo.keyStorePassword, is(equalTo("testnode"))); assertThat(ksKeyInfo.keyPassword, is(equalTo(ksKeyInfo.keyStorePassword))); assertThat(ksKeyInfo.keyStoreAlgorithm, is(KeyManagerFactory.getDefaultAlgorithm())); - assertThat(sslConfiguration.trustConfig(), is(sameInstance(ksKeyInfo))); + assertThat(sslConfiguration.trustConfig(), is(instanceOf(CombiningTrustConfig.class))); + assertCombiningTrustConfigContainsCorrectIssuers(sslConfiguration); } } public void testThatKeyPasswordCanBeSet() { Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", "path") - .put("xpack.security.ssl.keystore.password", "password") - .put("xpack.security.ssl.keystore.key_password", "key") + .put("keystore.path", "path") + .put("keystore.password", "password") + .put("keystore.key_password", "key") .build(); - SSLConfiguration sslConfiguration = new Global(settings); + SSLConfiguration sslConfiguration = new SSLConfiguration(settings); assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password"))); assertThat(ksKeyInfo.keyPassword, is(equalTo("key"))); - - // Pass settings in as profile settings - Settings profileSettings = settings.getByPrefix("xpack.security.ssl."); - SSLConfiguration sslConfiguration1 = new Custom(profileSettings, - randomBoolean() ? sslConfiguration : new Global(Settings.EMPTY)); - assertThat(sslConfiguration1.keyConfig(), instanceOf(StoreKeyConfig.class)); - ksKeyInfo = (StoreKeyConfig) sslConfiguration1.keyConfig(); - assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password"))); - assertThat(ksKeyInfo.keyPassword, is(equalTo("key"))); } @@ -97,26 +84,20 @@ public class SSLConfigurationTests extends ESTestCase { .put("truststore.path", "trust path") .put("truststore.password", "password for trust") .put("truststore.algorithm", "trusted") - .put("protocol", "ssl") - .put("session.cache_size", "3") - .put("session.cache_timeout", "10m") .build(); Settings serviceSettings = Settings.builder() - .put("xpack.security.ssl.keystore.path", "comp path") - .put("xpack.security.ssl.keystore.password", "comp password") - .put("xpack.security.ssl.keystore.key_password", "comp key") - .put("xpack.security.ssl.keystore.algorithm", "comp algo") - .put("xpack.security.ssl.truststore.path", "comp trust path") - .put("xpack.security.ssl.truststore.password", "comp password for trust") - .put("xpack.security.ssl.truststore.algorithm", "comp trusted") - .put("xpack.security.ssl.protocol", "tls") - .put("xpack.security.ssl.session.cache_size", "7") - .put("xpack.security.ssl.session.cache_timeout", "20m") + .put("xpack.ssl.keystore.path", "comp path") + .put("xpack.ssl.keystore.password", "comp password") + .put("xpack.ssl.keystore.key_password", "comp key") + .put("xpack.ssl.keystore.algorithm", "comp algo") + .put("xpack.ssl.truststore.path", "comp trust path") + .put("xpack.ssl.truststore.password", "comp password for trust") + .put("xpack.ssl.truststore.algorithm", "comp trusted") .build(); - SSLConfiguration globalSettings = new Global(serviceSettings); - SSLConfiguration sslConfiguration = new Custom(profileSettings, globalSettings); + SSLConfiguration globalSettings = new SSLConfiguration(serviceSettings); + SSLConfiguration sslConfiguration = new SSLConfiguration(profileSettings, globalSettings); assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); assertThat(ksKeyInfo.keyStorePath, is(equalTo("path"))); @@ -128,41 +109,31 @@ public class SSLConfigurationTests extends ESTestCase { assertThat(ksTrustInfo.trustStorePath, is(equalTo("trust path"))); assertThat(ksTrustInfo.trustStorePassword, is(equalTo("password for trust"))); assertThat(ksTrustInfo.trustStoreAlgorithm, is(equalTo("trusted"))); - assertThat(sslConfiguration.protocol(), is(equalTo("ssl"))); - assertThat(sslConfiguration.sessionCacheSize(), is(equalTo(3))); - assertThat(sslConfiguration.sessionCacheTimeout(), is(equalTo(TimeValue.timeValueMinutes(10L)))); } public void testThatEmptySettingsAreEqual() { - SSLConfiguration sslConfiguration = new Global(Settings.EMPTY); - SSLConfiguration sslConfiguration1 = new Global(Settings.EMPTY); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY); assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(true))); assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(true))); assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true))); assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true))); - SSLConfiguration profileSSLConfiguration = new Custom(Settings.EMPTY, sslConfiguration); + SSLConfiguration profileSSLConfiguration = new SSLConfiguration(Settings.EMPTY, sslConfiguration); assertThat(sslConfiguration.equals(profileSSLConfiguration), is(equalTo(true))); assertThat(profileSSLConfiguration.equals(sslConfiguration), is(equalTo(true))); assertThat(profileSSLConfiguration.equals(profileSSLConfiguration), is(equalTo(true))); } public void testThatSettingsWithDifferentKeystoresAreNotEqual() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.keystore.path", "path").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.keystore.path", "path1").build()); - assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false))); - assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false))); - assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true))); - assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true))); - } - - public void testThatSettingsWithDifferentProtocolsAreNotEqual() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.protocol", "ssl").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.protocol", "tls").build()); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() + .put("keystore.path", "path") + .put("keystore.password", randomAsciiOfLength(5)) + .build()); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() + .put("keystore.path", "path1") + .put("keystore.password", randomAsciiOfLength(5)) + .build()); assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false))); assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false))); assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true))); @@ -170,10 +141,14 @@ public class SSLConfigurationTests extends ESTestCase { } public void testThatSettingsWithDifferentTruststoresAreNotEqual() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.truststore.path", "/trust").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.truststore.path", "/truststore").build()); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() + .put("truststore.path", "/trust") + .put("truststore.password", randomAsciiOfLength(5)) + .build()); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() + .put("truststore.path", "/truststore") + .put("truststore.password", randomAsciiOfLength(5)) + .build()); assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false))); assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false))); assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true))); @@ -181,35 +156,35 @@ public class SSLConfigurationTests extends ESTestCase { } public void testThatEmptySettingsHaveSameHashCode() { - SSLConfiguration sslConfiguration = new Global(Settings.EMPTY); - SSLConfiguration sslConfiguration1 = new Global(Settings.EMPTY); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY); assertThat(sslConfiguration.hashCode(), is(equalTo(sslConfiguration1.hashCode()))); - SSLConfiguration profileSettings = new Custom(Settings.EMPTY, sslConfiguration); + SSLConfiguration profileSettings = new SSLConfiguration(Settings.EMPTY, sslConfiguration); assertThat(profileSettings.hashCode(), is(equalTo(sslConfiguration.hashCode()))); } public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.keystore.path", "path").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.keystore.path", "path1").build()); - assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode())))); - } - - public void testThatSettingsWithDifferentProtocolsHaveDifferentHashCode() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.protocol", "ssl").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.protocol", "tls").build()); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() + .put("keystore.path", "path") + .put("keystore.password", randomAsciiOfLength(5)) + .build()); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() + .put("keystore.path", "path1") + .put("keystore.password", randomAsciiOfLength(5)) + .build()); assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode())))); } public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() { - SSLConfiguration sslConfiguration = new Global(Settings.builder() - .put("xpack.security.ssl.truststore.path", "/trust").build()); - SSLConfiguration sslConfiguration1 = new Global(Settings.builder() - .put("xpack.security.ssl.truststore.path", "/truststore").build()); + SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() + .put("truststore.path", "/trust") + .put("truststore.password", randomAsciiOfLength(5)) + .build()); + SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() + .put("truststore.path", "/truststore") + .put("truststore.password", randomAsciiOfLength(5)) + .build()); assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode())))); } @@ -217,36 +192,37 @@ public class SSLConfigurationTests extends ESTestCase { Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); Settings settings = Settings.builder() - .put("xpack.security.ssl.key.path", + .put("key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) - .put("xpack.security.ssl.key.password", "testnode") - .put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .put("key_passphrase", "testnode") + .put("certificate", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) .build(); - SSLConfiguration config = new Global(settings); + SSLConfiguration config = new SSLConfiguration(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig(); KeyManager keyManager = keyConfig.createKeyManager(env); assertNotNull(keyManager); - assertThat(config.trustConfig(), sameInstance(keyConfig)); - TrustManager trustManager = keyConfig.createTrustManager(env); - assertNotNull(trustManager); + assertThat(config.trustConfig(), instanceOf(CombiningTrustConfig.class)); + assertCombiningTrustConfigContainsCorrectIssuers(config); } public void testConfigurationUsingPEMKeyAndTrustFiles() { Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); Settings settings = Settings.builder() - .put("xpack.security.ssl.key.path", + .put("key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) - .put("xpack.security.ssl.key.password", "testnode") - .put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) - .putArray("xpack.security.ssl.ca", + .put("key_passphrase", "testnode") + .put("certificate", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putArray("certificate_authorities", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(), getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt").toString()) .build(); - SSLConfiguration config = new Global(settings); + SSLConfiguration config = new SSLConfiguration(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig(); KeyManager keyManager = keyConfig.createKeyManager(env); @@ -256,4 +232,13 @@ public class SSLConfigurationTests extends ESTestCase { TrustManager trustManager = keyConfig.createTrustManager(env); assertNotNull(trustManager); } + + private void assertCombiningTrustConfigContainsCorrectIssuers(SSLConfiguration sslConfiguration) { + X509Certificate[] trustConfAcceptedIssuers = sslConfiguration.trustConfig().createTrustManager(null).getAcceptedIssuers(); + X509Certificate[] keyConfAcceptedIssuers = sslConfiguration.keyConfig().createTrustManager(null).getAcceptedIssuers(); + X509Certificate[] defaultAcceptedIssuers = DefaultJDKTrustConfig.INSTANCE.createTrustManager(null).getAcceptedIssuers(); + assertEquals(keyConfAcceptedIssuers.length + defaultAcceptedIssuers.length, trustConfAcceptedIssuers.length); + assertThat(Arrays.asList(keyConfAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers))); + assertThat(Arrays.asList(defaultAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers))); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java similarity index 92% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java index 6ff302e1ad0..cd0ed69859e 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLReloadIntegTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extension; @@ -71,7 +71,7 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { Settings settings = super.nodeSettings(nodeOrdinal); Settings.Builder builder = Settings.builder(); for (Entry entry : settings.getAsMap().entrySet()) { - if (entry.getKey().startsWith(Security.setting("ssl.")) == false) { + if (entry.getKey().startsWith("xpack.ssl.") == false) { builder.put(entry.getKey(), entry.getValue()); } } @@ -79,10 +79,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { builder.put("resource.reload.interval.high", "1s") .put(SecuritySettingsSource.getSSLSettingsForStore( "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode")) - .put("xpack.security.ssl.keystore.path", nodeStorePath); + .put("xpack.ssl.keystore.path", nodeStorePath); - if (builder.get("xpack.security.ssl.truststore.path") != null) { - builder.put("xpack.security.ssl.truststore.path", nodeStorePath); + if (builder.get("xpack.ssl.truststore.path") != null) { + builder.put("xpack.ssl.truststore.path", nodeStorePath); } return builder.build(); @@ -106,10 +106,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .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") + .put("xpack.ssl.keystore.path", keystorePath) + .put("xpack.ssl.keystore.password", "changeme") + .put("xpack.ssl.truststore.path", nodeStorePath) + .put("xpack.ssl.truststore.password", "testnode") .build(); String node = randomFrom(internalCluster().getNodeNames()); SSLService sslService = new SSLService(settings, new Environment(settings)); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java similarity index 58% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java rename to elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java index a4fc145d4c9..2622fa4b239 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/ssl/SSLServiceTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java @@ -3,7 +3,7 @@ * 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; +package org.elasticsearch.xpack.ssl; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; @@ -11,17 +11,14 @@ 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.xpack.XPackSettings; import org.junit.Before; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.nio.file.Path; @@ -29,11 +26,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static org.hamcrest.Matchers.arrayContainingInAnyOrder; 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.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; @@ -53,49 +49,33 @@ public class SSLServiceTests extends ESTestCase { 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 SSLService(settings, env); - 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") + .put("xpack.ssl.truststore.path", testnodeStore) + .put("xpack.ssl.truststore.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 customTruststoreSettings = Settings.builder() - .put("ssl.truststore.path", testClientStore) - .put("ssl.truststore.password", "testclient") + .put("truststore.path", testClientStore) + .put("truststore.password", "testclient") .build(); - SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings); + SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings, Settings.EMPTY); assertThat(sslEngineWithTruststore, is(not(nullValue()))); - SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); 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") + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") .build(); SSLService sslService = new SSLService(settings, env); @@ -109,11 +89,11 @@ public class SSLServiceTests extends ESTestCase { 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") + .put("xpack.ssl.keystore.path", differentPasswordsStore) + .put("xpack.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.key_password", "testnode1") .build(); - new SSLService(settings, env).createSSLEngine(Settings.EMPTY); + new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY); } public void testIncorrectKeyPasswordThrowsException() throws Exception { @@ -121,10 +101,10 @@ public class SSLServiceTests extends ESTestCase { 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") + .put("xpack.ssl.keystore.path", differentPasswordsStore) + .put("xpack.ssl.keystore.password", "testnode") .build(); - new SSLService(settings, env).createSSLEngine(Settings.EMPTY); + new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY); fail("expected an exception"); } catch (ElasticsearchException e) { assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory")); @@ -133,108 +113,142 @@ public class SSLServiceTests extends ESTestCase { public void testThatSSLv3IsNotEnabled() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") .build(); SSLService sslService = new SSLService(settings, env); - SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); + SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); 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(); - 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 { - 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(); - 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 { SSLService sslService = new SSLService(Settings.EMPTY, env); - SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); assertThat(sslEngine, notNullValue()); } public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.truststore.path", testclientStore) - .put("xpack.security.ssl.truststore.password", "testclient") + .put("xpack.ssl.truststore.path", testclientStore) + .put("xpack.ssl.truststore.password", "testclient") .build(); SSLService sslService = new SSLService(settings, env); - SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY); + SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); assertThat(sslEngine, notNullValue()); } + public void testCreateWithoutAnySettingsNotValidForServer() throws Exception { + SSLService sslService = new SSLService(Settings.EMPTY, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY)); + } + + public void testCreateWithOnlyTruststoreNotValidForServer() throws Exception { + Settings settings = Settings.builder() + .put("xpack.ssl.truststore.path", testnodeStore) + .put("xpack.ssl.truststore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY)); + } + + public void testCreateWithKeystoreIsValidForServer() throws Exception { + Settings settings = Settings.builder() + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY)); + } + + public void testValidForServerWithFallback() throws Exception { + Settings settings = Settings.builder() + .put("xpack.ssl.truststore.path", testnodeStore) + .put("xpack.ssl.truststore.password", "testnode") + .build(); + SSLService sslService = new SSLService(settings, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl."))); + + settings = Settings.builder() + .put("xpack.ssl.truststore.path", testnodeStore) + .put("xpack.ssl.truststore.password", "testnode") + .put("xpack.security.transport.ssl.keystore.path", testnodeStore) + .put("xpack.security.transport.ssl.keystore.password", "testnode") + .build(); + sslService = new SSLService(settings, env); + assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl."))); + assertTrue(sslService.isConfigurationValidForServerUsage( + settings.getByPrefix("xpack.security.transport.ssl."), settings.getByPrefix("xpack.ssl."))); + assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl."))); + } + + public void testGetVerificationMode() { + SSLService sslService = new SSLService(Settings.EMPTY, env); + assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(XPackSettings.VERIFICATION_MODE_DEFAULT)); + + Settings settings = Settings.builder() + .put("xpack.ssl.verification_mode", "none") + .put("xpack.security.transport.ssl.verification_mode", "certificate") + .put("transport.profiles.foo.xpack.security.ssl.verification_mode", "full") + .build(); + sslService = new SSLService(settings, env); + assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(VerificationMode.NONE)); + assertThat(sslService.getVerificationMode(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY), + is(VerificationMode.CERTIFICATE)); + assertThat(sslService.getVerificationMode(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."), + settings.getByPrefix("xpack.security.transport.ssl.")), is(VerificationMode.FULL)); + assertThat(sslService.getVerificationMode(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl.")), + is(VerificationMode.CERTIFICATE)); + } + + public void testIsSSLClientAuthEnabled() { + SSLService sslService = new SSLService(Settings.EMPTY, env); + assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY)); + assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY)); + + Settings settings = Settings.builder() + .put("xpack.ssl.client_authentication", "none") + .put("xpack.security.transport.ssl.client_authentication", "optional") + .build(); + sslService = new SSLService(settings, env); + assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY)); + assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY)); + assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl."))); + assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY)); + assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."), + settings.getByPrefix("xpack.security.transport.ssl."))); + } + 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) + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") + .put("xpack.ssl.truststore.path", testnodeStore) .build(); - IllegalArgumentException e = - expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); - assertThat(e.getMessage(), is("no truststore password configured")); + NullPointerException e = + expectThrows(NullPointerException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("truststore password must be specified")); } public void testThatKeystorePasswordIsRequired() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.path", testnodeStore) .build(); - IllegalArgumentException e = - expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); - assertThat(e.getMessage(), is("no keystore password configured")); + NullPointerException e = + expectThrows(NullPointerException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("keystore password must be specified")); } public void testCiphersAndInvalidCiphersWork() throws Exception { - List ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS); + List ciphers = new ArrayList<>(XPackSettings.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()])) + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") + .putArray("xpack.ssl.ciphers", ciphers.toArray(new String[ciphers.size()])) .build(); SSLService sslService = new SSLService(settings, env); - SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY); + SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); assertThat(engine, is(notNullValue())); String[] enabledCiphers = engine.getEnabledCipherSuites(); assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar"))); @@ -242,9 +256,9 @@ public class SSLServiceTests extends ESTestCase { 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" }) + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.ssl.keystore.password", "testnode") + .putArray("xpack.ssl.cipher_suites", new String[]{"foo", "bar"}) .build(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env)); @@ -253,18 +267,19 @@ public class SSLServiceTests extends ESTestCase { public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testnodeStore) - .put("xpack.security.ssl.keystore.password", "testnode") + .put("xpack.ssl.keystore.path", testnodeStore) + .put("xpack.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); + final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), config.cipherSuites(), 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))); + // the order we set the protocols in is not going to be what is returned as internally the JDK may sort the versions + assertThat(socket.getEnabledProtocols(), arrayContainingInAnyOrder(config.supportedProtocols().toArray(Strings.EMPTY_ARRAY))); } } @@ -283,8 +298,8 @@ public class SSLServiceTests extends ESTestCase { @Network public void testThatSSLContextTrustsJDKTrustedCAs() throws Exception { Settings settings = Settings.builder() - .put("xpack.security.ssl.keystore.path", testclientStore) - .put("xpack.security.ssl.keystore.password", "testclient") + .put("xpack.ssl.keystore.path", testclientStore) + .put("xpack.ssl.keystore.password", "testclient") .build(); SSLContext sslContext = new SSLService(settings, env).sslContext(); try (CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build()) { @@ -292,21 +307,5 @@ public class SSLServiceTests extends ESTestCase { // certs are trusted by default client.execute(new HttpGet("https://www.elastic.co/")).close(); } - - 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 = 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 - // trust any public CAs - client.execute(new HttpGet("https://www.elastic.co/")); - fail("A SSLHandshakeException should have been thrown here"); - } catch (Exception e) { - assertThat(e, instanceOf(SSLHandshakeException.class)); - } } } diff --git a/elasticsearch/x-pack/security/src/test/resources/org/elasticsearch/xpack/security/ssl/instances.yml b/elasticsearch/x-pack/src/test/resources/org/elasticsearch/xpack/ssl/instances.yml similarity index 100% rename from elasticsearch/x-pack/security/src/test/resources/org/elasticsearch/xpack/security/ssl/instances.yml rename to elasticsearch/x-pack/src/test/resources/org/elasticsearch/xpack/ssl/instances.yml diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java index 0d845d1b8b7..78e8ca95185 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.common.text.TextTemplateEngine; +import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.watcher.actions.Action; import org.elasticsearch.xpack.watcher.actions.Action.Result.Status; import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext; @@ -224,8 +225,8 @@ public class WebhookActionTests extends ESTestCase { public void testThatSelectingProxyWorks() throws Exception { Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment); - httpClient.start(); + HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment, + new SSLService(environment.settings(), environment)); MockWebServer proxyServer = new MockWebServer(); try { diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java index 983e31f7bd2..f3af18ff56f 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java @@ -50,8 +50,8 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest Path resource = getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks"); return Settings.builder() .put(super.nodeSettings(nodeOrdinal)) - .put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString()) - .put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode") + .put("xpack.http.ssl.keystore.path", resource.toString()) + .put("xpack.http.ssl.keystore.password", "testnode") .build(); }