diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index d55ba3ca06a..ddbeed9bbc1 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -11,6 +11,7 @@ import org.apache.logging.log4j.util.Supplier; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -173,14 +174,18 @@ public class PkiRealm extends Realm { private static X509TrustManager trustManagersFromTruststore(String truststorePath, RealmConfig realmConfig) { final Settings settings = realmConfig.settings(); - String password = SSL_SETTINGS.truststorePassword.get(settings).orElseThrow(() -> new IllegalArgumentException( + if (SSL_SETTINGS.truststorePassword.exists(settings) == false) { + throw new IllegalArgumentException( "[" + RealmSettings.getFullSettingKey(realmConfig, SSL_SETTINGS.truststorePassword) + "] is not configured" - )); - String trustStoreAlgorithm = SSL_SETTINGS.truststoreAlgorithm.get(settings); - try { - return CertUtils.trustManager(truststorePath, password, trustStoreAlgorithm, realmConfig.env()); - } catch (Exception e) { - throw new IllegalArgumentException("failed to load specified truststore", e); + ); + } + try (SecureString password = SSL_SETTINGS.truststorePassword.get(settings)) { + String trustStoreAlgorithm = SSL_SETTINGS.truststoreAlgorithm.get(settings); + try { + return CertUtils.trustManager(truststorePath, password.getChars(), trustStoreAlgorithm, realmConfig.env()); + } catch (Exception e) { + throw new IllegalArgumentException("failed to load specified truststore", e); + } } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java index 246892aa1cf..0dcc9411db4 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/CertUtils.java @@ -155,14 +155,14 @@ public class CertUtils { * @param env the environment to use for file resolution. May be {@code null} * @return a trust manager with the trust material from the store */ - public static X509ExtendedTrustManager trustManager(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm, + public static X509ExtendedTrustManager trustManager(String trustStorePath, char[] trustStorePassword, String trustStoreAlgorithm, @Nullable Environment env) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException { 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()); + trustStore.load(in, trustStorePassword); return trustManager(trustStore, trustStoreAlgorithm); } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java index 2bad70508d6..229bec35ec0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/PEMKeyConfig.java @@ -5,11 +5,6 @@ */ package org.elasticsearch.xpack.ssl; -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.settings.SecureString; -import org.elasticsearch.env.Environment; - import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509ExtendedTrustManager; import java.io.IOException; @@ -29,39 +24,43 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import org.apache.lucene.util.IOUtils; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.env.Environment; + /** * Implementation of a key configuration that is backed by a PEM encoded key file and one or more certificates */ class PEMKeyConfig extends KeyConfig { private final String keyPath; - private final String keyPassword; + private final SecureString keyPassword; private final String certPath; /** * 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 keyPassword the password for the key. * @param certChainPath the path to the file containing the certificate chain */ - PEMKeyConfig(String keyPath, String keyPassword, String certChainPath) { + PEMKeyConfig(String keyPath, SecureString keyPassword, String certChainPath) { this.keyPath = Objects.requireNonNull(keyPath, "key file must be specified"); - this.keyPassword = keyPassword; + this.keyPassword = Objects.requireNonNull(keyPassword).clone(); this.certPath = Objects.requireNonNull(certChainPath, "certificate must be specified"); } @Override X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { try { - PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment)); + PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment), keyPassword); if (privateKey == null) { throw new IllegalArgumentException("private key [" + keyPath + "] could not be loaded"); } Certificate[] certificateChain = CertUtils.readCertificates(Collections.singletonList(certPath), environment); - // password must be non-null for keystore... - try (SecureString securedKeyPasswordChars = new SecureString(keyPassword == null ? new char[0] : keyPassword.toCharArray())) { - return CertUtils.keyManager(certificateChain, privateKey, securedKeyPasswordChars.getChars()); - } + + return CertUtils.keyManager(certificateChain, privateKey, keyPassword.getChars()); } catch (IOException | UnrecoverableKeyException | NoSuchAlgorithmException | CertificateException | KeyStoreException e) { throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e); } @@ -70,22 +69,15 @@ class PEMKeyConfig extends KeyConfig { @Override List privateKeys(@Nullable Environment environment) { try { - return Collections.singletonList(readPrivateKey(CertUtils.resolvePath(keyPath, environment))); + return Collections.singletonList(readPrivateKey(CertUtils.resolvePath(keyPath, environment), keyPassword)); } catch (IOException e) { throw new UncheckedIOException("failed to read key", e); } } - private PrivateKey readPrivateKey(Path keyPath) throws IOException { - try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8); - SecureString secureString = new SecureString(keyPassword == null ? new char[0] : keyPassword.toCharArray())) { - return CertUtils.readPrivateKey(reader, () -> { - if (keyPassword == null) { - return null; - } else { - return secureString.getChars(); - } - }); + private static PrivateKey readPrivateKey(Path keyPath, SecureString keyPassword) throws IOException { + try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) { + return CertUtils.readPrivateKey(reader, keyPassword::getChars); } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java index 759c50d27ac..dce50294683 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.ssl; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; @@ -26,7 +27,7 @@ public final 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 SSLConfigurationSettings SETTINGS_PARSER = SSLConfigurationSettings.withoutPrefix(); + static final SSLConfigurationSettings SETTINGS_PARSER = SSLConfigurationSettings.withoutPrefix(); private final KeyConfig keyConfig; private final TrustConfig trustConfig; @@ -181,25 +182,31 @@ public final class SSLConfiguration { 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", ""), + // TODO: we should not support loading a keystore from sysprops... + try (SecureString keystorePassword = new SecureString(System.getProperty("javax.net.ssl.keyStorePassword", ""))) { + return new StoreKeyConfig(System.getProperty("javax.net.ssl.keyStore"), + keystorePassword, keystorePassword, System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); + } } return KeyConfig.NONE; } if (keyPath != null) { - String keyPassword = SETTINGS_PARSER.keyPassword.get(settings).orElse(null); + SecureString keyPassword = SETTINGS_PARSER.keyPassword.get(settings); String certPath = SETTINGS_PARSER.cert.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 = SETTINGS_PARSER.keystorePassword.get(settings).orElse(null); + SecureString keyStorePassword = SETTINGS_PARSER.keystorePassword.get(settings); String keyStoreAlgorithm = SETTINGS_PARSER.keystoreAlgorithm.get(settings); - String keyStoreKeyPassword = SETTINGS_PARSER.keystoreKeyPassword.get(settings).orElse(keyStorePassword); + SecureString keyStoreKeyPassword = SETTINGS_PARSER.keystoreKeyPassword.get(settings);; + if (keyStoreKeyPassword.length() == 0) { + keyStoreKeyPassword = keyStorePassword; + } String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.get(settings); return new StoreKeyConfig(keyStorePath, keyStorePassword, keyStoreKeyPassword, keyStoreAlgorithm, trustStoreAlgorithm); } @@ -223,13 +230,14 @@ public final class SSLConfiguration { } else if (caPaths != null) { return new PEMTrustConfig(caPaths); } else if (trustStorePath != null) { - String trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings).orElse(null); + SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings); String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.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", ""), + try (SecureString truststorePassword = new SecureString(System.getProperty("javax.net.ssl.trustStorePassword", ""))) { + return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"), truststorePassword, System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); + } } else if (global != null && keyConfig == global.keyConfig()) { return global.trustConfig(); } else if (keyConfig != KeyConfig.NONE) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java index ac099931009..c8ac6640291 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java @@ -5,40 +5,51 @@ */ package org.elasticsearch.xpack.ssl; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Settings; - import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Function; +import org.elasticsearch.common.settings.SecureSetting; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.settings.Setting; +import org.elasticsearch.common.settings.Settings; + +import org.elasticsearch.common.settings.Setting.Property; + /** * Bridges {@link SSLConfiguration} into the {@link Settings} framework, using {@link Setting} objects. */ public class SSLConfigurationSettings { - private final String prefix; - public final Setting> ciphers; public final Setting> supportedProtocols; public final Setting> keystorePath; - public final Setting> keystorePassword; + public final Setting keystorePassword; public final Setting keystoreAlgorithm; - public final Setting> keystoreKeyPassword; + public final Setting keystoreKeyPassword; public final Setting> truststorePath; - public final Setting> truststorePassword; + public final Setting truststorePassword; public final Setting truststoreAlgorithm; public final Setting> keyPath; - public final Setting> keyPassword; + public final Setting keyPassword; public final Setting> cert; public final Setting> caPaths; public final Setting> clientAuth; public final Setting> verificationMode; + // pkg private for tests + final Setting legacyKeystorePassword; + final Setting legacyKeystoreKeyPassword; + final Setting legacyTruststorePassword; + final Setting legacyKeyPassword; + + private final List> allSettings; + /** * @see #withoutPrefix * @see #withPrefix @@ -47,72 +58,46 @@ public class SSLConfigurationSettings { */ private SSLConfigurationSettings(String prefix) { assert prefix != null : "Prefix cannot be null (but can be blank)"; - this.prefix = prefix; - ciphers = list("cipher_suites", Collections.emptyList()); - supportedProtocols = list("supported_protocols", Collections.emptyList()); - keystorePath = optionalString("keystore.path"); - keystorePassword = optionalString("keystore.password"); - keystoreKeyPassword = optionalString("keystore.key_password", keystorePassword); - truststorePath = optionalString("truststore.path"); - truststorePassword = optionalString("truststore.password"); - keystoreAlgorithm = systemProperty("keystore.algorithm", - "ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()); - truststoreAlgorithm = systemProperty("truststore.algorithm", "ssl.TrustManagerFactory.algorithm", - TrustManagerFactory.getDefaultAlgorithm()); - keyPath = optionalString("key"); - keyPassword = optionalString("key_passphrase"); - cert = optionalString("certificate"); - caPaths = list("certificate_authorities", Collections.emptyList()); - clientAuth = optional("client_authentication", SSLClientAuth::parse); - verificationMode = optional("verification_mode", VerificationMode::parse); + ciphers = Setting.listSetting(prefix + "cipher_suites", Collections.emptyList(), Function.identity(), + Property.NodeScope, Property.Filtered); + supportedProtocols = Setting.listSetting(prefix + "supported_protocols", Collections.emptyList(), Function.identity(), + Property.NodeScope, Property.Filtered); + keystorePath = new Setting<>(prefix + "keystore.path", s -> null, Optional::ofNullable, + Property.NodeScope, Property.Filtered); + legacyKeystorePassword = new Setting<>(prefix + "keystore.password", "", SecureString::new, + Property.Deprecated, Property.Filtered, Property.NodeScope); + keystorePassword = SecureSetting.secureString(prefix + "keystore.secure_password", legacyKeystorePassword); + legacyKeystoreKeyPassword = new Setting<>(prefix + "keystore.key_password", "", + SecureString::new, Property.Deprecated, Property.Filtered, Property.NodeScope); + keystoreKeyPassword = SecureSetting.secureString(prefix + "keystore.secure_key_password", legacyKeystoreKeyPassword); + truststorePath = new Setting<>(prefix + "truststore.path", s -> null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + legacyTruststorePassword = new Setting<>(prefix + "truststore.password", "", SecureString::new, + Property.Deprecated, Property.Filtered, Property.NodeScope); + truststorePassword = SecureSetting.secureString(prefix + "truststore.secure_password", legacyTruststorePassword); + keystoreAlgorithm = new Setting<>(prefix + "keystore.algorithm", s -> KeyManagerFactory.getDefaultAlgorithm(), + Function.identity(), Property.NodeScope, Property.Filtered); + truststoreAlgorithm = new Setting<>(prefix + "truststore.algorithm", s -> TrustManagerFactory.getDefaultAlgorithm(), + Function.identity(), Property.NodeScope, Property.Filtered); + keyPath = new Setting<>(prefix + "key", s -> null, Optional::ofNullable, Setting.Property.NodeScope, Setting.Property.Filtered); + legacyKeyPassword = new Setting<>(prefix + "key_passphrase", "", SecureString::new, + Property.Deprecated, Property.Filtered, Property.NodeScope); + keyPassword = SecureSetting.secureString(prefix + "secure_key_passphrase", legacyKeyPassword); + cert =new Setting<>(prefix + "certificate", s -> null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + caPaths = Setting.listSetting(prefix + "certificate_authorities", Collections.emptyList(), Function.identity(), + Property.NodeScope, Property.Filtered); + clientAuth = new Setting<>(prefix + "client_authentication", (String) null, + s -> s == null ? Optional.empty() : Optional.of(SSLClientAuth.parse(s)), Property.NodeScope, Property.Filtered); + verificationMode = new Setting<>(prefix + "verification_mode", (String) null, + s -> s == null ? Optional.empty() : Optional.of(VerificationMode.parse(s)), Property.NodeScope, Property.Filtered); + + this.allSettings = Arrays.asList(ciphers, supportedProtocols, keystorePath, keystorePassword, keystoreAlgorithm, + keystoreKeyPassword, truststorePath, truststorePassword, truststoreAlgorithm, keyPath, keyPassword, cert, caPaths, + clientAuth, verificationMode, legacyKeystorePassword, legacyKeystoreKeyPassword, legacyKeyPassword, legacyTruststorePassword); } public List> getAllSettings() { - return Arrays.asList(ciphers, supportedProtocols, - keystorePath, keystorePassword, keystoreAlgorithm, keystoreKeyPassword, - truststorePath, truststorePassword, truststoreAlgorithm, - keyPath, keyPassword, - cert, caPaths, clientAuth, verificationMode); - } - - private Setting> optionalString(String keyPart) { - return optionalString(keyPart, (s) -> null); - } - - private Setting> optionalString(String keyPart, Function defaultValue) { - return new Setting<>(prefix + keyPart, defaultValue, Optional::ofNullable, - Setting.Property.NodeScope, Setting.Property.Filtered); - } - - private Setting> optionalString(String keyPart, Setting> fallback) { - return new Setting<>(prefix + keyPart, fallback, Optional::ofNullable, - Setting.Property.NodeScope, Setting.Property.Filtered); - } - - private Setting> optional(String keyPart, Function parserIfNotNull) { - Function> parser = s -> { - if (s == null) { - return Optional.empty(); - } else { - return Optional.of(parserIfNotNull.apply(s)); - } - }; - return new Setting<>(prefix + keyPart, (String) null, parser, Setting.Property.NodeScope, Setting.Property.Filtered); - } - - private Setting systemProperty(String keyPart, String systemProperty, String defaultValue) { - return string(keyPart, s -> System.getProperty(systemProperty, defaultValue)); - } - - private Setting string(String keyPart, Function defaultFunction) { - return new Setting<>(prefix + keyPart, defaultFunction, Function.identity(), - Setting.Property.NodeScope, Setting.Property.Filtered); - } - - private Setting> list(String keyPart, List defaultValue) { - return Setting.listSetting(prefix + keyPart, defaultValue, Function.identity(), - Setting.Property.NodeScope, Setting.Property.Filtered); + return allSettings; } /** diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java index b3b92adcb55..d095ce95828 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreKeyConfig.java @@ -35,9 +35,9 @@ import java.util.Objects; class StoreKeyConfig extends KeyConfig { final String keyStorePath; - final String keyStorePassword; + final SecureString keyStorePassword; final String keyStoreAlgorithm; - final String keyPassword; + final SecureString keyPassword; final String trustStoreAlgorithm; /** @@ -48,11 +48,13 @@ class StoreKeyConfig extends KeyConfig { * @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, + StoreKeyConfig(String keyStorePath, SecureString keyStorePassword, SecureString 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; + // since we support reloading the keystore, we must store the passphrase in memory for the life of the node, so we + // clone the password and never close it during our uses below + this.keyStorePassword = Objects.requireNonNull(keyStorePassword, "keystore password must be specified").clone(); + this.keyPassword = Objects.requireNonNull(keyPassword).clone(); this.keyStoreAlgorithm = keyStoreAlgorithm; this.trustStoreAlgorithm = trustStoreAlgorithm; } @@ -62,9 +64,7 @@ class StoreKeyConfig extends KeyConfig { try { KeyStore ks = getKeyStore(environment); checkKeyStore(ks); - try (SecureString keyPasswordSecureString = new SecureString(keyPassword.toCharArray())) { - return CertUtils.keyManager(ks, keyPasswordSecureString.getChars(), keyStoreAlgorithm); - } + return CertUtils.keyManager(ks, keyPassword.getChars(), keyStoreAlgorithm); } catch (IOException | CertificateException | NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) { throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e); } @@ -73,7 +73,7 @@ class StoreKeyConfig extends KeyConfig { @Override X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { - return CertUtils.trustManager(keyStorePath, keyStorePassword, trustStoreAlgorithm, environment); + return CertUtils.trustManager(keyStorePath, keyStorePassword.getChars(), trustStoreAlgorithm, environment); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } @@ -88,19 +88,17 @@ class StoreKeyConfig extends KeyConfig { List privateKeys(@Nullable Environment environment) { try { KeyStore keyStore = getKeyStore(environment); - try (SecureString keyPasswordSecureString = new SecureString(keyPassword.toCharArray())) { - List privateKeys = new ArrayList<>(); - for (Enumeration e = keyStore.aliases(); e.hasMoreElements(); ) { - final String alias = e.nextElement(); - if (keyStore.isKeyEntry(alias)) { - Key key = keyStore.getKey(alias, keyPasswordSecureString.getChars()); - if (key instanceof PrivateKey) { - privateKeys.add((PrivateKey) key); - } + List privateKeys = new ArrayList<>(); + for (Enumeration e = keyStore.aliases(); e.hasMoreElements(); ) { + final String alias = e.nextElement(); + if (keyStore.isKeyEntry(alias)) { + Key key = keyStore.getKey(alias, keyPassword.getChars()); + if (key instanceof PrivateKey) { + privateKeys.add((PrivateKey) key); } } - return privateKeys; } + return privateKeys; } catch (Exception e) { throw new ElasticsearchException("failed to list keys", e); } @@ -111,12 +109,7 @@ class StoreKeyConfig extends KeyConfig { try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) { // TODO remove reliance on JKS since we can use PKCS12 stores in JDK8+... KeyStore ks = KeyStore.getInstance("jks"); - if (keyStorePassword == null) { - throw new IllegalArgumentException("keystore password may not be null"); - } - try (SecureString keyStorePasswordSecureString = new SecureString(keyStorePassword.toCharArray())) { - ks.load(in, keyStorePasswordSecureString.getChars()); - } + ks.load(in, keyStorePassword.getChars()); return ks; } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java index d635e14e155..608b86742e3 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/StoreTrustConfig.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ssl; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.env.Environment; import javax.net.ssl.X509ExtendedTrustManager; @@ -21,7 +22,7 @@ import java.util.Objects; class StoreTrustConfig extends TrustConfig { final String trustStorePath; - final String trustStorePassword; + final SecureString trustStorePassword; final String trustStoreAlgorithm; /** @@ -30,17 +31,18 @@ class StoreTrustConfig extends TrustConfig { * @param trustStorePassword the password for the truststore * @param trustStoreAlgorithm the algorithm to use for reading the truststore */ - StoreTrustConfig(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) { + StoreTrustConfig(String trustStorePath, SecureString trustStorePassword, String trustStoreAlgorithm) { this.trustStorePath = trustStorePath; - this.trustStorePassword = trustStorePath != null ? - Objects.requireNonNull(trustStorePassword, "truststore password must be specified") : trustStorePassword; + // since we support reloading the truststore, we must store the passphrase in memory for the life of the node, so we + // clone the password and never close it during our uses below + this.trustStorePassword = Objects.requireNonNull(trustStorePassword, "truststore password must be specified").clone(); this.trustStoreAlgorithm = trustStoreAlgorithm; } @Override X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { try { - return CertUtils.trustManager(trustStorePath, trustStorePassword, trustStoreAlgorithm, environment); + return CertUtils.trustManager(trustStorePath, trustStorePassword.getChars(), trustStoreAlgorithm, environment); } catch (Exception e) { throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e); } diff --git a/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java b/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java index a3603674f9d..1b63b8baa72 100644 --- a/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java @@ -14,11 +14,13 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.logging.ESLoggerFactory; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.security.action.rolemapping.PutRoleMappingRequestBuilder; import org.elasticsearch.xpack.security.action.rolemapping.PutRoleMappingResponse; import org.elasticsearch.xpack.security.authc.ldap.LdapRealm; @@ -139,8 +141,8 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase Path store = getDataPath(TESTNODE_KEYSTORE); Settings.Builder builder = Settings.builder(); if (useGlobalSSL) { - builder.put(super.nodeSettings(nodeOrdinal).filter((s) -> s.startsWith("xpack.ssl.") == false)) - .put(sslSettingsForStore(store, "testnode")); + builder.put(super.nodeSettings(nodeOrdinal).filter((s) -> s.startsWith("xpack.ssl.") == false)); + addSslSettingsForStore(builder, store, "testnode"); } else { builder.put(super.nodeSettings(nodeOrdinal)); } @@ -198,10 +200,10 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase protected Settings transportClientSettings() { if (useGlobalSSL) { Path store = getDataPath(TESTNODE_KEYSTORE); - return Settings.builder() - .put(super.transportClientSettings().filter((s) -> s.startsWith("xpack.ssl.") == false)) - .put(sslSettingsForStore(store, "testnode")) - .build(); + Settings.Builder builder = Settings.builder() + .put(super.transportClientSettings().filter((s) -> s.startsWith("xpack.ssl.") == false)); + addSslSettingsForStore(builder, store, "testnode"); + return builder.build(); } else { return super.transportClientSettings(); } @@ -285,13 +287,14 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase return UsernamePasswordToken.basicAuthHeaderValue(username, new SecureString(password.toCharArray())); } - private Settings sslSettingsForStore(Path store, String password) { - return Settings.builder() - .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(); + private void addSslSettingsForStore(Settings.Builder builder, Path store, String password) { + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString("xpack.ssl.keystore.secure_password", password); + secureSettings.setString("xpack.ssl.truststore.secure_password", password); + }); + builder.put("xpack.ssl.keystore.path", store) + .put("xpack.ssl.verification_mode", "certificate") + .put("xpack.ssl.truststore.path", store); } static class RoleMappingEntry { diff --git a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java index 41c86ad2808..2d4a1e9d6b9 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java @@ -19,6 +19,7 @@ import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.network.NetworkAddress; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; @@ -198,11 +199,17 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { @Override protected Settings nodeSettings(int nodeOrdinal) { - return Settings.builder().put(super.nodeSettings(nodeOrdinal)) - .put(customSecuritySettingsSource.nodeSettings(nodeOrdinal)) + Settings.Builder builder = Settings.builder().put(super.nodeSettings(nodeOrdinal)) // Disable native ML autodetect_process as the c++ controller won't be available - .put(MachineLearning.AUTODETECT_PROCESS.getKey(), false) - .build(); + .put(MachineLearning.AUTODETECT_PROCESS.getKey(), false); + Settings customSettings = customSecuritySettingsSource.nodeSettings(nodeOrdinal); + builder.put(customSettings.getAsMap()); // handle secure settings separately + Settings.Builder customBuilder = Settings.builder().put(customSettings); + if (customBuilder.getSecureSettings() != null) { + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> + secureSettings.merge((MockSecureSettings) customBuilder.getSecureSettings())); + } + return builder.build(); } @Override diff --git a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index db6a49ab9a6..17485f1d3e9 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -9,6 +9,8 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.analysis.common.CommonAnalysisPlugin; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.PathUtils; +import org.elasticsearch.common.settings.MockSecureSettings; +import org.elasticsearch.common.settings.SecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -34,6 +36,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.function.Consumer; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; @@ -77,6 +80,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas private final String subfolderPrefix; private final boolean useGeneratedSSLConfig; private final boolean hostnameVerificationEnabled; + private final boolean usePEM; /** * Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration. @@ -92,6 +96,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas this.subfolderPrefix = scope.name(); this.useGeneratedSSLConfig = useGeneratedSSLConfig; this.hostnameVerificationEnabled = randomBoolean(); + this.usePEM = randomBoolean(); } private Path nodePath(final Path parentFolder, final String subfolderPrefix, final int nodeOrdinal) { @@ -121,8 +126,8 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas .put("xpack.security.authc.realms.file.type", FileRealm.TYPE) .put("xpack.security.authc.realms.file.order", 0) .put("xpack.security.authc.realms.index.type", NativeRealm.TYPE) - .put("xpack.security.authc.realms.index.order", "1") - .put(getNodeSSLSettings()); + .put("xpack.security.authc.realms.index.order", "1"); + addNodeSSLSettings(builder); return builder.build(); } @@ -133,8 +138,8 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas @Override public Settings transportClientSettings() { - Settings.Builder builder = Settings.builder().put(super.transportClientSettings()) - .put(getClientSSLSettings()); + Settings.Builder builder = Settings.builder().put(super.transportClientSettings()); + addClientSSLSettings(builder, ""); if (randomBoolean()) { builder.put(Security.USER_SETTING.getKey(), transportClientUsername() + ":" + new String(transportClientPassword().getChars())); @@ -188,32 +193,36 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas return XPackPlugin.class; } - public Settings getNodeSSLSettings() { - if (randomBoolean()) { - return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", - "/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"), - useGeneratedSSLConfig, hostnameVerificationEnabled, false); - } - return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode", + private void addNodeSSLSettings(Settings.Builder builder) { + if (usePEM) { + addSSLSettingsForPEMFiles(builder, "", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", + "/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"), useGeneratedSSLConfig, hostnameVerificationEnabled, false); + + } else { + addSSLSettingsForStore(builder, "", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", + "testnode", useGeneratedSSLConfig, hostnameVerificationEnabled, false); + } } - public Settings getClientSSLSettings() { - if (randomBoolean()) { - return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem", "testclient", - "/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"), - useGeneratedSSLConfig, hostnameVerificationEnabled, true); - } - - return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient", + public void addClientSSLSettings(Settings.Builder builder, String prefix) { + if (usePEM) { + addSSLSettingsForPEMFiles(builder, prefix, + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem", "testclient", + "/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"), useGeneratedSSLConfig, hostnameVerificationEnabled, true); + } else { + addSSLSettingsForStore(builder, prefix, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", + "testclient", useGeneratedSSLConfig, hostnameVerificationEnabled, true); + } } /** @@ -221,56 +230,83 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas * * @param resourcePathToStore the location of the keystore or truststore * @param password the password - * @return the configuration settings */ - public static Settings getSSLSettingsForStore(String resourcePathToStore, String password) { - return getSSLSettingsForStore(resourcePathToStore, password, false, true, true); + public static void addSSLSettingsForStore(Settings.Builder builder, String resourcePathToStore, String password) { + addSSLSettingsForStore(builder, "", resourcePathToStore, password, false, true, true); } - private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean useGeneratedSSLConfig, - boolean hostnameVerificationEnabled, boolean transportClient) { + private static void addSSLSettingsForStore(Settings.Builder builder, String prefix, String resourcePathToStore, String password, + boolean useGeneratedSSLConfig, boolean hostnameVerificationEnabled, + boolean transportClient) { Path store = resolveResourcePath(resourcePathToStore); - Settings.Builder builder = Settings.builder(); - if (transportClient == false) { - builder.put("xpack.security.http.ssl.enabled", false); + builder.put(prefix + "xpack.security.http.ssl.enabled", false); } - builder.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); + builder.put(prefix + "xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); if (useGeneratedSSLConfig == false) { - builder.put("xpack.ssl.keystore.path", store) - .put("xpack.ssl.keystore.password", password); + builder.put(prefix + "xpack.ssl.keystore.path", store); + if (transportClient) { + // continue using insecure settings for clients until we figure out what to do there... + builder.put(prefix + "xpack.ssl.keystore.password", password); + } else { + addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "xpack.ssl.keystore.secure_password", password)); + } } - if (useGeneratedSSLConfig == false && randomBoolean()) { - builder.put("xpack.ssl.truststore.path", store) - .put("xpack.ssl.truststore.password", password); + if (useGeneratedSSLConfig == false && true /*randomBoolean()*/) { + builder.put(prefix + "xpack.ssl.truststore.path", store); + if (transportClient) { + // continue using insecure settings for clients until we figure out what to do there... + builder.put(prefix + "xpack.ssl.truststore.password", password); + } else { + addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "xpack.ssl.truststore.secure_password", password)); + } } - return builder.build(); } - private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, String certificatePath, - List trustedCertificates, boolean useGeneratedSSLConfig, - boolean hostnameVerificationEnabled, boolean transportClient) { - Settings.Builder builder = Settings.builder(); + private static void addSSLSettingsForPEMFiles(Settings.Builder builder, String prefix, String keyPath, String password, + String certificatePath, List trustedCertificates, boolean useGeneratedSSLConfig, + boolean hostnameVerificationEnabled, boolean transportClient) { if (transportClient == false) { - builder.put("xpack.security.http.ssl.enabled", false); + builder.put(prefix + "xpack.security.http.ssl.enabled", false); } - builder.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); + builder.put(prefix + "xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); if (useGeneratedSSLConfig == false) { - builder.put("xpack.ssl.key", resolveResourcePath(keyPath)) - .put("xpack.ssl.key_passphrase", password) - .put("xpack.ssl.certificate", resolveResourcePath(certificatePath)); + builder.put(prefix + "xpack.ssl.key", resolveResourcePath(keyPath)) + .put(prefix + "xpack.ssl.certificate", resolveResourcePath(certificatePath)); + if (transportClient) { + // continue using insecure settings for clients until we figure out what to do there... + builder.put(prefix + "xpack.ssl.key_passphrase", password); + } else { + addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "xpack.ssl.secure_key_passphrase", password)); + } if (trustedCertificates.isEmpty() == false) { - builder.put("xpack.ssl.certificate_authorities", + builder.put(prefix + "xpack.ssl.certificate_authorities", Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates))); } } - return builder.build(); + } + + public static void addSecureSettings(Settings.Builder builder, Consumer settingsSetter) { + SecureSettings secureSettings = builder.getSecureSettings(); + if (secureSettings instanceof MockSecureSettings) { + settingsSetter.accept((MockSecureSettings) secureSettings); + } else if (secureSettings == null) { + MockSecureSettings mockSecureSettings = new MockSecureSettings(); + settingsSetter.accept(mockSecureSettings); + builder.setSecureSettings(mockSecureSettings); + } else { + throw new AssertionError("Test settings builder must contain MockSecureSettings, " + + "but has [" + secureSettings.getClass().getName() + "]"); + } } private static String[] resolvePathsToString(List resourcePaths) { diff --git a/plugin/src/test/java/org/elasticsearch/test/SettingsFilterTests.java b/plugin/src/test/java/org/elasticsearch/test/SettingsFilterTests.java index cca337325dc..aca5c937ccb 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SettingsFilterTests.java +++ b/plugin/src/test/java/org/elasticsearch/test/SettingsFilterTests.java @@ -8,6 +8,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.MockSecureSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsFilter; @@ -30,6 +31,7 @@ public class SettingsFilterTests extends ESTestCase { private Settings.Builder configuredSettingsBuilder = Settings.builder(); private Map settingsMatcherMap = new HashMap<>(); + private MockSecureSettings mockSecureSettings = new MockSecureSettings(); public void testFiltering() throws Exception { configureUnfilteredSetting("xpack.security.authc.realms.file.type", "file"); @@ -53,7 +55,7 @@ public class SettingsFilterTests extends ESTestCase { configureUnfilteredSetting("xpack.security.authc.realms.pki1.order", "0"); configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks").toString()); - configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.password", "truststore-testnode-only"); + configureSecureSetting("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only"); configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.algorithm", "SunX509"); configureFilteredSetting("xpack.ssl.keystore.path", @@ -61,10 +63,10 @@ public class SettingsFilterTests extends ESTestCase { 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"); + configureSecureSetting("xpack.ssl.keystore.secure_password", "testnode"); configureFilteredSetting("xpack.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm()); - configureFilteredSetting("xpack.ssl.keystore.key_password", "testnode"); - configureFilteredSetting("xpack.ssl.truststore.password", randomAlphaOfLength(5)); + configureSecureSetting("xpack.ssl.keystore.secure_key_password", "testnode"); + configureSecureSetting("xpack.ssl.truststore.secure_password", randomAlphaOfLength(5)); configureFilteredSetting("xpack.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm()); // client profile @@ -75,11 +77,11 @@ public class SettingsFilterTests extends ESTestCase { 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.ssl.keystore.password", "testnode"); + configureSecureSetting("transport.profiles.client.xpack.security.ssl.keystore.secure_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", randomAlphaOfLength(5)); + configureSecureSetting("transport.profiles.client.xpack.security.ssl.keystore.secure_key_password", "testnode"); + configureSecureSetting("transport.profiles.client.xpack.security.ssl.truststore.secure_password", randomAlphaOfLength(5)); configureFilteredSetting("transport.profiles.client.xpack.security.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm()); @@ -93,6 +95,7 @@ public class SettingsFilterTests extends ESTestCase { Settings settings = Settings.builder() .put("path.home", createTempDir()) .put(configuredSettingsBuilder.build()) + .setSecureSettings(mockSecureSettings) .build(); XPackPlugin xPackPlugin = new XPackPlugin(settings, null); @@ -126,6 +129,11 @@ public class SettingsFilterTests extends ESTestCase { configureSetting(settingName, value, is(nullValue())); } + private void configureSecureSetting(String settingName, String value) { + mockSecureSettings.setString(settingName, value); + settingsMatcherMap.put(settingName, is(nullValue())); + } + private void configureSetting(String settingName, String value, Matcher expectedMatcher) { configuredSettingsBuilder.put(settingName, value); settingsMatcherMap.put(settingName, expectedMatcher); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java b/plugin/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java index 389078a52a1..9f1e85d2a29 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/common/http/HttpClientTests.java @@ -9,6 +9,7 @@ import com.carrotsearch.randomizedtesting.generators.RandomStrings; import org.apache.http.client.ClientProtocolException; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; @@ -164,25 +165,28 @@ public class HttpClientTests extends ESTestCase { public void testHttps() throws Exception { Path resource = getDataPath("/org/elasticsearch/xpack/security/keystore/truststore-testnode-only.jks"); - + MockSecureSettings secureSettings = new MockSecureSettings(); Settings settings; if (randomBoolean()) { + secureSettings.setString("xpack.http.ssl.truststore.secure_password", "truststore-testnode-only"); settings = Settings.builder() .put("xpack.http.ssl.truststore.path", resource.toString()) - .put("xpack.http.ssl.truststore.password", "truststore-testnode-only") + .setSecureSettings(secureSettings) .build(); } else { + secureSettings.setString("xpack.ssl.truststore.secure_password", "truststore-testnode-only"); settings = Settings.builder() .put("xpack.ssl.truststore.path", resource.toString()) - .put("xpack.ssl.truststore.password", "truststore-testnode-only") + .setSecureSettings(secureSettings) .build(); } httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); - + secureSettings = new MockSecureSettings(); // We can't use the client created above for the server since it is only a truststore + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings2 = Settings.builder() .put("xpack.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks")) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); TestsSSLService sslService = new TestsSSLService(settings2, environment); @@ -191,28 +195,32 @@ public class HttpClientTests extends ESTestCase { public void testHttpsDisableHostnameVerification() throws Exception { Path resource = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-no-subjaltname.jks"); - Settings settings; if (randomBoolean()) { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.http.ssl.truststore.secure_password", "testnode-no-subjaltname"); settings = Settings.builder() .put("xpack.http.ssl.truststore.path", resource.toString()) - .put("xpack.http.ssl.truststore.password", "testnode-no-subjaltname") .put("xpack.http.ssl.verification_mode", randomFrom(VerificationMode.NONE, VerificationMode.CERTIFICATE)) + .setSecureSettings(secureSettings) .build(); } else { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode-no-subjaltname"); settings = Settings.builder() .put("xpack.ssl.truststore.path", resource.toString()) - .put("xpack.ssl.truststore.password", "testnode-no-subjaltname") .put("xpack.ssl.verification_mode", randomFrom(VerificationMode.NONE, VerificationMode.CERTIFICATE)) + .setSecureSettings(secureSettings) .build(); } httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); - + MockSecureSettings secureSettings = new MockSecureSettings(); // We can't use the client created above for the server since it only defines a truststore + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode-no-subjaltname"); Settings settings2 = Settings.builder() .put("xpack.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-no-subjaltname.jks")) - .put("xpack.ssl.keystore.password", "testnode-no-subjaltname") + .setSecureSettings(secureSettings) .build(); TestsSSLService sslService = new TestsSSLService(settings2, environment); @@ -221,9 +229,11 @@ public class HttpClientTests extends ESTestCase { public void testHttpsClientAuth() throws Exception { Path resource = getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", resource.toString()) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); TestsSSLService sslService = new TestsSSLService(settings, environment); @@ -417,7 +427,7 @@ public class HttpClientTests extends ESTestCase { }); HttpRequest request = HttpRequest.builder("localhost", serverSocket.getLocalPort()).path("/").build(); expectThrows(ClientProtocolException.class, () -> httpClient.execute(request)); - assertThat("A server side exception occured, but shouldnt", hasExceptionHappened.get(), is(nullValue())); + assertThat("A server side exception occured, but shouldn't", hasExceptionHappened.get(), is(nullValue())); } finally { terminate(executor); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java index 648f88d0b19..97b99b152ac 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java @@ -19,6 +19,7 @@ public class TokenPassphraseBootstrapCheckTests extends ESTestCase { public void testTokenPassphraseCheck() throws Exception { assertTrue(new TokenPassphraseBootstrapCheck(Settings.EMPTY).check()); MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("foo", "bar"); // leniency in setSecureSettings... if its empty it's skipped Settings settings = Settings.builder().setSecureSettings(secureSettings).build(); assertTrue(new TokenPassphraseBootstrapCheck(settings).check()); @@ -36,6 +37,7 @@ public class TokenPassphraseBootstrapCheckTests extends ESTestCase { Settings settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false).build(); assertFalse(new TokenPassphraseBootstrapCheck(settings).check()); MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("foo", "bar"); // leniency in setSecureSettings... if its empty it's skipped settings = Settings.builder().put(settings).setSecureSettings(secureSettings).build(); assertFalse(new TokenPassphraseBootstrapCheck(settings).check()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java index 419c5c96612..3cf26c38c5d 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java @@ -187,9 +187,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { SecuritySettingsSource.DEFAULT_PASSWORD); if (useGeneratedSSL == false) { - for (Map.Entry entry : cluster2SettingsSource.getClientSSLSettings().getAsMap().entrySet()) { - builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue()); - } + cluster2SettingsSource.addClientSSLSettings(builder, "xpack.security.audit.index.client."); } if (useSecurity == false && builder.get(NetworkModule.TRANSPORT_TYPE_KEY) == null) { builder.put("xpack.security.audit.index.client." + NetworkModule.TRANSPORT_TYPE_KEY, diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java index 753c43de635..5c5de9d0eb8 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java @@ -103,9 +103,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase { .put("xpack.security.audit.index.client.cluster.name", clusterName) .put("xpack.security.audit.index.client.xpack.security.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD); - for (Map.Entry entry : getClientSSLSettings().getAsMap().entrySet()) { - builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue()); - } + addClientSSLSettings(builder, "xpack.security.audit.index.client."); return builder.build(); } }; diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java index facf8b10f7b..66b42330a44 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RealmSettingsTests.java @@ -14,6 +14,7 @@ import java.util.stream.Collectors; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.extensions.XPackExtension; import org.elasticsearch.xpack.security.authc.support.Hasher; @@ -77,7 +78,7 @@ public class RealmSettingsTests extends ESTestCase { } public void testActiveDirectoryRealmWithAllSettingsValidatesSuccessfully() throws Exception { - assertSuccess(activeDirectoryRealm("ad1")); + assertSuccess(activeDirectoryRealm("ad1", true)); } public void testPkiRealmWithCertificateAuthoritiesValidatesSuccessfully() throws Exception { @@ -98,7 +99,7 @@ public class RealmSettingsTests extends ESTestCase { .put(fileRealm("file1").build()) .put(nativeRealm("native2").build()) .put(ldapRealm("ldap3", true, false).build()) - .put(activeDirectoryRealm("ad4").build()) + .put(activeDirectoryRealm("ad4", false).build()) // don't load SSL twice .put(pkiRealm("pki5", false).build()) .build(); assertSuccess(settings); @@ -125,7 +126,7 @@ public class RealmSettingsTests extends ESTestCase { } private Settings.Builder ldapSettings(boolean userSearch, boolean groupSearch) { - final Settings.Builder builder = commonLdapSettings("ldap") + final Settings.Builder builder = commonLdapSettings("ldap", true) .put("bind_dn", "elasticsearch") .put("bind_password", "t0p_s3cr3t") .put("follow_referrals", randomBoolean()); @@ -157,12 +158,12 @@ public class RealmSettingsTests extends ESTestCase { return builder; } - private Settings.Builder activeDirectoryRealm(String name) { - return realm(name, activeDirectorySettings()); + private Settings.Builder activeDirectoryRealm(String name, boolean configureSSL) { + return realm(name, activeDirectorySettings(configureSSL)); } - private Settings.Builder activeDirectorySettings() { - final Settings.Builder builder = commonLdapSettings("active_directory") + private Settings.Builder activeDirectorySettings(boolean configureSSL) { + final Settings.Builder builder = commonLdapSettings("active_directory", configureSSL) .put("domain_name", "MEGACORP"); builder.put("user_search.base_dn", "o=people, dc.example, dc.com"); builder.put("user_search.scope", "sub_tree"); @@ -172,7 +173,7 @@ public class RealmSettingsTests extends ESTestCase { return builder; } - private Settings.Builder commonLdapSettings(String type) { + private Settings.Builder commonLdapSettings(String type, boolean configureSSL) { final Settings.Builder builder = baseSettings(type, true) .putArray("url", "ldap://dir1.internal:9876", "ldap://dir2.internal:9876", "ldap://dir3.internal:9876") .put("load_balance.type", "round_robin") @@ -182,7 +183,9 @@ public class RealmSettingsTests extends ESTestCase { .put("timeout.tcp_connect", randomPositiveTimeValue()) .put("timeout.tcp_read", randomPositiveTimeValue()) .put("timeout.ldap_search", randomPositiveTimeValue()); - configureSsl("ssl.", builder, randomBoolean(), randomBoolean()); + if (configureSSL) { + configureSsl("ssl.", builder, randomBoolean(), randomBoolean()); + } return builder; } @@ -197,7 +200,9 @@ public class RealmSettingsTests extends ESTestCase { if (useTrustStore) { builder.put("truststore.path", randomAlphaOfLengthBetween(8, 32)); - builder.put("truststore.password", randomAlphaOfLengthBetween(4, 12)); + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString("keystore.secure_password", randomAlphaOfLength(8)); + }); builder.put("truststore.algorithm", randomAlphaOfLengthBetween(6, 10)); } else { builder.putArray("certificate_authorities", generateRandomStringArray(5, 32, false, false)); @@ -208,17 +213,22 @@ public class RealmSettingsTests extends ESTestCase { private Settings.Builder configureSsl(String prefix, Settings.Builder builder, boolean useKeyStore, boolean useTrustStore) { if (useKeyStore) { builder.put(prefix + "keystore.path", "x-pack/ssl/" + randomAlphaOfLength(5) + ".jks"); - builder.put(prefix + "keystore.password", randomAlphaOfLength(8)); - builder.put(prefix + "keystore.key_password", randomAlphaOfLength(8)); + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString(prefix + "keystore.secure_password", randomAlphaOfLength(8)); + secureSettings.setString(prefix + "keystore.secure_key_password", randomAlphaOfLength(8)); + }); } else { builder.put(prefix + "key", "x-pack/ssl/" + randomAlphaOfLength(5) + ".key"); - builder.put(prefix + "key_passphrase", randomAlphaOfLength(32)); + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "secure_key_passphrase", randomAlphaOfLength(32))); + builder.put(prefix + "certificate", "x-pack/ssl/" + randomAlphaOfLength(5) + ".cert"); } if (useTrustStore) { builder.put(prefix + "truststore.path", "x-pack/ssl/" + randomAlphaOfLength(5) + ".jts"); - builder.put(prefix + "truststore.password", randomAlphaOfLength(8)); + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "truststore.secure_password", randomAlphaOfLength(8))); } else { builder.put(prefix + "certificate_authorities", "x-pack/ssl/" + randomAlphaOfLength(8) + ".ca"); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java index a5362a2cd13..a25f99438c2 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java @@ -119,8 +119,8 @@ public class TokenServiceTests extends ESTestCase { try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) { // verify a second separate token service with its own passphrase cannot verify MockSecureSettings secureSettings = new MockSecureSettings(); - Settings settings = Settings.builder().setSecureSettings(secureSettings).build(); secureSettings.setString(TokenService.TOKEN_PASSPHRASE.getKey(), randomAlphaOfLengthBetween(8, 30)); + Settings settings = Settings.builder().setSecureSettings(secureSettings).build(); TokenService anotherService = new TokenService(settings, Clock.systemUTC(), internalClient, lifecycleService); PlainActionFuture future = new PlainActionFuture<>(); anotherService.getAndValidateToken(requestContext, future); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java index c1651382f37..cdc0dab8941 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java @@ -81,13 +81,13 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase { String password = new String(CharArrays.toUtf8Bytes(nodeClientPassword().getChars()), StandardCharsets.UTF_8); String url = getHttpURL(); ESNativeRealmMigrateTool.MigrateUserOrRoles muor = new ESNativeRealmMigrateTool.MigrateUserOrRoles(); - Settings sslSettings = - SecuritySettingsSource.getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", - "testnode"); - Settings settings = Settings.builder().put(sslSettings) + + Settings.Builder builder = Settings.builder() .put("path.home", home) - .put("path.conf", conf) - .build(); + .put("path.conf", conf); + SecuritySettingsSource.addSSLSettingsForStore(builder, + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); + Settings settings = builder.build(); logger.error("--> retrieving users using URL: {}, home: {}", url, home); OptionParser parser = muor.getParser(); @@ -126,10 +126,10 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase { String password = new String(CharArrays.toUtf8Bytes(nodeClientPassword().getChars()), StandardCharsets.UTF_8); String url = getHttpURL(); ESNativeRealmMigrateTool.MigrateUserOrRoles muor = new ESNativeRealmMigrateTool.MigrateUserOrRoles(); - Settings sslSettings = - SecuritySettingsSource.getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", - "testclient"); - Settings settings = Settings.builder().put(sslSettings).put("path.home", home).build(); + Settings.Builder builder = Settings.builder().put("path.home", home); + SecuritySettingsSource.addSSLSettingsForStore(builder, + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient"); + Settings settings = builder.build(); logger.error("--> retrieving roles using URL: {}, home: {}", url, home); OptionParser parser = muor.getParser(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java index c13737b1536..6cad51fef23 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapTestUtils.java @@ -11,6 +11,7 @@ import com.unboundid.ldap.sdk.LDAPConnection; import com.unboundid.ldap.sdk.LDAPConnectionOptions; import com.unboundid.ldap.sdk.LDAPURL; import org.apache.lucene.util.LuceneTestCase; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; @@ -28,22 +29,23 @@ public class LdapTestUtils { public static LDAPConnection openConnection(String url, String bindDN, String bindPassword, Path truststore) throws Exception { boolean useGlobalSSL = ESTestCase.randomBoolean(); Settings.Builder builder = Settings.builder().put("path.home", LuceneTestCase.createTempDir()); + MockSecureSettings secureSettings = new MockSecureSettings(); + builder.setSecureSettings(secureSettings); if (useGlobalSSL) { - builder.put("xpack.ssl.truststore.path", truststore) - .put("xpack.ssl.truststore.password", "changeit"); - + builder.put("xpack.ssl.truststore.path", truststore); // fake realm to load config with certificate verification mode builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore); - builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit"); builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); + secureSettings.setString("xpack.ssl.truststore.secure_password", "changeit"); + secureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit"); } else { // fake realms so ssl will get loaded builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore); - builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit"); builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL); builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore); - builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit"); builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE); + secureSettings.setString("xpack.security.authc.realms.foo.ssl.truststore.secure_password", "changeit"); + secureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit"); } Settings settings = builder.build(); Environment env = new Environment(settings); @@ -60,8 +62,10 @@ public class LdapTestUtils { if (useGlobalSSL) { connectionSettings = Settings.EMPTY; } else { + MockSecureSettings connSecureSettings = new MockSecureSettings(); + connSecureSettings.setString("truststore.secure_password", "changeit"); connectionSettings = Settings.builder().put("truststore.path", truststore) - .put("truststore.password", "changeit").build(); + .setSecureSettings(connSecureSettings).build(); } return LdapUtils.privilegedConnect(() -> new LDAPConnection(sslService.sslSocketFactory(connectionSettings), options, ldapurl.getHost(), ldapurl.getPort(), bindDN, bindPassword)); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java index c9fe0280c25..cf41ff9da4d 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapUserSearchSessionFactoryTests.java @@ -15,6 +15,7 @@ import com.unboundid.ldap.sdk.SimpleBindRequest; import com.unboundid.ldap.sdk.SingleServerSet; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; @@ -58,14 +59,21 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase { * If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname * verification tests since a re-established connection does not perform hostname verification. */ + globalSettings = Settings.builder() .put("path.home", createTempDir()) .put("xpack.ssl.truststore.path", keystore) - .put("xpack.ssl.truststore.password", "changeit") + .setSecureSettings(newSecureSettings("xpack.ssl.truststore.secure_password", "changeit")) .build(); sslService = new SSLService(globalSettings, env); } + private MockSecureSettings newSecureSettings(String key, String value) { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString(key, value); + return secureSettings; + } + public void testSupportsUnauthenticatedSessions() throws Exception { RealmConfig config = new RealmConfig("ldap_realm", Settings.builder() .put(buildLdapSettings(ldapUrls(), Strings.EMPTY_ARRAY, "", LdapSearchScope.SUB_TREE)) diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java index 859804e0819..2ac9cc59477 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java @@ -15,9 +15,11 @@ import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.http.HttpServerTransport; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.common.socket.SocketAccess; import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.file.FileRealm; @@ -38,7 +40,7 @@ import java.security.SecureRandom; import java.util.Locale; import java.util.Map.Entry; -import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; +import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForStore; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; @@ -51,10 +53,10 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { @Override protected Settings nodeSettings(int nodeOrdinal) { SSLClientAuth sslClientAuth = randomBoolean() ? SSLClientAuth.REQUIRED : SSLClientAuth.OPTIONAL; - return Settings.builder() + + Settings.Builder builder = Settings.builder() .put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) - .put("xpack.security.http.ssl.enabled", true) .put("xpack.security.http.ssl.client_authentication", sslClientAuth) .put("xpack.security.authc.realms.file.type", FileRealm.TYPE) @@ -63,9 +65,11 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { .put("xpack.security.authc.realms.pki1.order", "1") .put("xpack.security.authc.realms.pki1.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.authc.realms.pki1.truststore.password", "truststore-testnode-only") - .put("xpack.security.authc.realms.pki1.files.role_mapping", getDataPath("role_mapping.yml")) - .build(); + .put("xpack.security.authc.realms.pki1.files.role_mapping", getDataPath("role_mapping.yml")); + + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> + secureSettings.setString("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only")); + return builder.build(); } @Override @@ -74,8 +78,9 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { } public void testTransportClientCanAuthenticateViaPki() { - Settings settings = getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); - try (TransportClient client = createTransportClient(settings)) { + Settings.Builder builder = Settings.builder(); + addSSLSettingsForStore(builder, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); + try (TransportClient client = createTransportClient(builder.build())) { client.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses())); IndexResponse response = client.prepareIndex("foo", "bar").setSource("pki", "auth").get(); assertEquals(DocWriteResponse.Result.CREATED, response.getResult()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java index 7922bc09348..2f5518aec3a 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.RestClient; import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.SecurityIntegTestCase; @@ -42,7 +43,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { protected Settings nodeSettings(int nodeOrdinal) { String randomClientPortRange = randomClientPort + "-" + (randomClientPort+100); - return Settings.builder() + Settings.Builder builder = Settings.builder() .put(super.nodeSettings(nodeOrdinal)) .put(NetworkModule.HTTP_ENABLED.getKey(), true) .put("xpack.security.http.ssl.enabled", true) @@ -53,12 +54,15 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { .put("xpack.security.authc.realms.pki1.order", "1") .put("xpack.security.authc.realms.pki1.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.security.authc.realms.pki1.truststore.password", "truststore-testnode-only") .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_authentication", SSLClientAuth.OPTIONAL) - .build(); + .put("transport.profiles.want_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.OPTIONAL); + + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> + secureSettings.setString("xpack.security.authc.realms.pki1.truststore.secure_password", "truststore-testnode-only")); + return builder.build(); + } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java index 2e1ce61a548..e3e9d4c17b7 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java @@ -18,6 +18,7 @@ import java.util.regex.Pattern; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -139,9 +140,11 @@ public class PkiRealmTests extends ESTestCase { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = mock(UserRoleMapper.class); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("truststore.password", "testnode") + .setSecureSettings(secureSettings) .build(); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings)), roleMapper); @@ -167,10 +170,12 @@ public class PkiRealmTests extends ESTestCase { public void testVerificationFailsUsingADifferentTruststore() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = mock(UserRoleMapper.class); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("truststore.secure_password", "testnode-client-profile"); Settings settings = Settings.builder() .put("truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks")) - .put("truststore.password", "testnode-client-profile") + .setSecureSettings(secureSettings) .build(); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings)), roleMapper); @@ -200,7 +205,7 @@ public class PkiRealmTests extends ESTestCase { new ThreadContext(globalSettings)), mock(UserRoleMapper.class)); fail("exception should have been thrown"); } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), containsString("[xpack.security.authc.realms.mypki.truststore.password] is not configured")); + assertThat(e.getMessage(), containsString("[xpack.security.authc.realms.mypki.truststore.secure_password] is not configured")); } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java index 81436cdb19c..85c2a76352c 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java @@ -15,6 +15,7 @@ import org.elasticsearch.node.MockNode; import org.elasticsearch.node.Node; import org.elasticsearch.node.NodeValidationException; import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.discovery.TestZenDiscovery; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.XPackPlugin; @@ -30,7 +31,7 @@ import java.nio.file.Path; import java.util.Arrays; import static java.util.Collections.singletonMap; -import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; +import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForStore; import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile; import static org.hamcrest.CoreMatchers.is; @@ -55,27 +56,27 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase Path store; try { - store = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"); + store = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); assertThat(Files.exists(store), is(true)); } catch (Exception e) { throw new RuntimeException(e); } - settingsBuilder.put("transport.profiles.client.xpack.security.ssl.truststore.path", store) // settings for client truststore - .put("transport.profiles.client.xpack.security.ssl.truststore.password", "testclient") - .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED); + settingsBuilder.put(super.nodeSettings(nodeOrdinal)) + .put("transport.profiles.client.xpack.security.ssl.truststore.path", store) // settings for client truststore + .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("transport.profiles.default.type", "node") + .put("transport.profiles.client.xpack.security.type", "client") + .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("xpack.security.audit.enabled", false) + .put(XPackSettings.WATCHER_ENABLED.getKey(), false) + .put(TestZenDiscovery.USE_MOCK_PINGS.getKey(), false); - return settingsBuilder - .put(super.nodeSettings(nodeOrdinal)) - .put("transport.profiles.default.type", "node") - .put("transport.profiles.client.xpack.security.type", "client") - .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("xpack.security.audit.enabled", false) - .put(XPackSettings.WATCHER_ENABLED.getKey(), false) - .put(TestZenDiscovery.USE_MOCK_PINGS.getKey(), false) - .build(); + SecuritySettingsSource.addSecureSettings(settingsBuilder, secureSettings -> + secureSettings.setString("transport.profiles.client.xpack.security.ssl.truststore.secure_password", "testnode")); + return settingsBuilder.build(); } public void testThatConnectionToServerTypeConnectionWorks() throws IOException, NodeValidationException { @@ -88,8 +89,8 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase String unicastHost = NetworkAddress.format(transportAddress.address()); // test that starting up a node works - Settings nodeSettings = Settings.builder() - .put(getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode")) + Settings.Builder nodeSettings = Settings.builder() + .put() .put("node.name", "my-test-node") .put("network.host", "localhost") .put("cluster.name", internalCluster().getClusterName()) @@ -102,9 +103,9 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase .put(NetworkModule.HTTP_ENABLED.getKey(), false) .put(Node.NODE_MASTER_SETTING.getKey(), false) .put(TestZenDiscovery.USE_MOCK_PINGS.getKey(), false) - .put("xpack.ml.autodetect_process", false) - .build(); - try (Node node = new MockNode(nodeSettings, Arrays.asList(XPackPlugin.class, TestZenDiscovery.TestPlugin.class))) { + .put("xpack.ml.autodetect_process", false); + addSSLSettingsForStore(nodeSettings, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); + try (Node node = new MockNode(nodeSettings.build(), Arrays.asList(XPackPlugin.class, TestZenDiscovery.TestPlugin.class))) { node.start(); ensureStableCluster(cluster().size() + 1); } @@ -123,10 +124,9 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase String unicastHost = NetworkAddress.format(transportAddress.address()); // test that starting up a node works - Settings nodeSettings = Settings.builder() + Settings.Builder nodeSettings = Settings.builder() .put("xpack.security.authc.realms.file.type", FileRealm.TYPE) .put("xpack.security.authc.realms.file.order", 0) - .put(getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient")) .put("node.name", "my-test-node") .put(Security.USER_SETTING.getKey(), "test_user:changeme") .put("cluster.name", internalCluster().getClusterName()) @@ -140,9 +140,9 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase .put("path.home", home) .put(Node.NODE_MASTER_SETTING.getKey(), false) .put(TestZenDiscovery.USE_MOCK_PINGS.getKey(), false) - .put("xpack.ml.autodetect_process", false) - .build(); - try (Node node = new MockNode(nodeSettings, Arrays.asList(XPackPlugin.class, TestZenDiscovery.TestPlugin.class))) { + .put("xpack.ml.autodetect_process", false); + addSSLSettingsForStore(nodeSettings, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); + try (Node node = new MockNode(nodeSettings.build(), Arrays.asList(XPackPlugin.class, TestZenDiscovery.TestPlugin.class))) { node.start(); // assert that node is not connected by waiting for the timeout diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java index 9a0cfc9d2f5..34d96cd2dc5 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.ssl.CertUtils; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -93,7 +94,7 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase { public Settings nodeSettings(int nodeOrdinal) { Settings defaultSettings = super.nodeSettings(nodeOrdinal); Settings.Builder builder = Settings.builder() - .put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false)) + .put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false).getAsMap()) .put("transport.host", hostName); Path keystorePath = nodeConfigPath(nodeOrdinal).resolve("keystore.jks"); try (OutputStream os = Files.newOutputStream(keystorePath)) { @@ -103,10 +104,12 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase { } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { throw new ElasticsearchException("unable to write keystore for node", e); } + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString("xpack.ssl.keystore.secure_password", "changeme"); + secureSettings.setString("xpack.ssl.truststore.secure_password", "changeme"); + }); builder.put("xpack.ssl.keystore.path", keystorePath.toAbsolutePath()) - .put("xpack.ssl.keystore.password", "changeme") - .put("xpack.ssl.truststore.path", keystorePath.toAbsolutePath()) - .put("xpack.ssl.truststore.password", "changeme"); + .put("xpack.ssl.truststore.path", keystorePath.toAbsolutePath()); List unicastHosts = Arrays.stream(defaultSettings.getAsArray("discovery.zen.ping.unicast.hosts")) .map((s) -> { String port = s.substring(s.lastIndexOf(':'), s.length()); @@ -130,10 +133,12 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase { } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { throw new ElasticsearchException("unable to write keystore for node", e); } + SecuritySettingsSource.addSecureSettings(builder, secureSettings -> { + secureSettings.setString("xpack.ssl.keystore.secure_password", "changeme"); + secureSettings.setString("xpack.ssl.truststore.secure_password", "changeme"); + }); builder.put("xpack.ssl.keystore.path", path.toAbsolutePath()) - .put("xpack.ssl.keystore.password", "changeme") - .put("xpack.ssl.truststore.path", path.toAbsolutePath()) - .put("xpack.ssl.truststore.password", "changeme"); + .put("xpack.ssl.truststore.path", path.toAbsolutePath()); return builder.build(); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java index 19ca290600f..ddbc039da64 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java @@ -6,8 +6,10 @@ package org.elasticsearch.xpack.security.transport.netty4; import org.elasticsearch.client.Client; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.xpack.ssl.SSLClientAuth; @@ -30,7 +32,7 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { protected Settings nodeSettings(int nodeOrdinal) { Settings settings = super.nodeSettings(nodeOrdinal); Settings.Builder builder = Settings.builder() - .put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false)); + .put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false).getAsMap()); settings = builder.build(); // The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP @@ -52,10 +54,12 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { throw new RuntimeException(e); } + SecuritySettingsSource.addSecureSettings(settingsBuilder, secureSettings -> { + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode-ip-only"); + secureSettings.setString("xpack.ssl.truststore.secure_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.ssl.client_authentication", SSLClientAuth.NONE) diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java index a9f8c8318cf..197418aea7e 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HttpServerTransportTests.java @@ -9,6 +9,7 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.ssl.SslHandler; import org.elasticsearch.common.network.NetworkService; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.env.Environment; @@ -43,10 +44,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { @Before public void createSSLService() throws Exception { Path testNodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testNodeStore) - .put("xpack.ssl.keystore.password", "testnode") .put("path.home", createTempDir()) + .setSecureSettings(secureSettings) .build(); env = new Environment(settings); sslService = new SSLService(settings, env); @@ -171,10 +174,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { } public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true) .put("path.home", createTempDir()) .build(); @@ -187,10 +192,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase { } public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .put("path.home", createTempDir()) .build(); env = new Environment(settings); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java index a99b7fd6773..563ada3deb8 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java @@ -10,6 +10,7 @@ import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.ssl.SslHandler; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.network.NetworkService; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.env.Environment; @@ -37,9 +38,11 @@ public class SecurityNetty4TransportTests extends ESTestCase { @Before public void createSSLService() throws Exception { Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .put("path.home", createTempDir()) .build(); env = new Environment(settings); @@ -177,14 +180,16 @@ public class SecurityNetty4TransportTests extends ESTestCase { } public void testTransportSSLOverridesGlobalSSL() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode"); + secureSettings.setString("xpack.ssl.truststore.secure_password", "truststore-testnode-only"); 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("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) - .put("xpack.ssl.truststore.password", "truststore-testnode-only") + .setSecureSettings(secureSettings) .put("path.home", createTempDir()); Settings settings = builder.build(); env = new Environment(settings); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java index 98b629a0e18..24fbc30bd9f 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java @@ -8,9 +8,11 @@ package org.elasticsearch.xpack.security.transport.netty4; import org.elasticsearch.client.Client; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.TestXPackTransportClient; @@ -19,7 +21,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Map.Entry; -import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsString; @@ -52,10 +53,12 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase { throw new RuntimeException(e); } + SecuritySettingsSource.addSecureSettings(settingsBuilder, secureSettings -> { + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode-no-subjaltname"); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode-no-subjaltname"); + }); 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(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java index 6ff3038a28f..3ed07bcbc37 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java @@ -10,7 +10,6 @@ import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.BasicCredentialsProvider; @@ -38,7 +37,7 @@ import java.security.KeyStore; import java.security.SecureRandom; import java.util.Locale; -import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; +import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForStore; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; @@ -95,10 +94,9 @@ public class SslIntegrationTests extends SecurityIntegTestCase { } public void testThatConnectionToHTTPWorks() throws Exception { - Settings settings = Settings.builder() - .put(getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient")) - .build(); - SSLService service = new SSLService(settings, null); + Settings.Builder builder = Settings.builder(); + addSSLSettingsForStore(builder, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient"); + SSLService service = new SSLService(builder.build(), null); CredentialsProvider provider = new BasicCredentialsProvider(); provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nodeClientUsername(), diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java index 8afc2264031..924da45c488 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java @@ -19,11 +19,10 @@ import org.junit.BeforeClass; import java.net.InetAddress; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Map.Entry; import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD; import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_USER_NAME; -import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; +import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForStore; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsString; @@ -138,9 +137,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { * set to trust the testclient-client-profile certificate so the connection should always succeed */ public void testThatProfileTransportClientCanConnectToClientProfile() throws Exception { - Settings settings = getSSLSettingsForStore( + Settings.Builder builder = Settings.builder(); + addSSLSettingsForStore(builder, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"); - try (TransportClient transportClient = createTransportClient(settings)) { + try (TransportClient transportClient = createTransportClient(builder.build())) { transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client"))); assertGreenClusterState(transportClient); } @@ -153,9 +153,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { * authentication */ public void testThatProfileTransportClientCanConnectToNoClientAuthProfile() throws Exception { - Settings settings = getSSLSettingsForStore( + Settings.Builder builder = Settings.builder(); + addSSLSettingsForStore(builder, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"); - try (TransportClient transportClient = createTransportClient(settings)) { + try (TransportClient transportClient = createTransportClient(builder.build())) { transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_client_auth"))); assertGreenClusterState(transportClient); @@ -169,9 +170,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase { * so the connection should always fail */ public void testThatProfileTransportClientCannotConnectToDefaultProfile() throws Exception { - Settings settings = getSSLSettingsForStore( + Settings.Builder builder = Settings.builder(); + addSSLSettingsForStore(builder, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"); - try (TransportClient transportClient = createTransportClient(settings)) { + try (TransportClient transportClient = createTransportClient(builder.build())) { TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()); transportClient.addTransportAddress(transportAddress); transportClient.admin().cluster().prepareHealth().get(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java index 470308e0c7f..83a9b542392 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.ssl; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; @@ -19,13 +20,15 @@ public class SSLBootstrapCheckTests extends ESTestCase { public void testSSLBootstrapCheckWithKey() throws Exception { final String keyPrefix = randomBoolean() ? "security.transport." : ""; + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack." + keyPrefix + "ssl.key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient") .put("xpack." + keyPrefix + "ssl.certificate", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) + .setSecureSettings(secureSettings) .build(); final Environment env = randomBoolean() ? new Environment(settings) : null; SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env); @@ -34,16 +37,18 @@ public class SSLBootstrapCheckTests extends ESTestCase { public void testSSLBootstrapCheckWithDefaultCABeingTrusted() throws Exception { final String keyPrefix = randomBoolean() ? "security.transport." : ""; + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack." + keyPrefix + "ssl.key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient") .put("xpack." + keyPrefix + "ssl.certificate", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) .putArray("xpack." + keyPrefix + "ssl.certificate_authorities", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt").toString(), getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) + .setSecureSettings(secureSettings) .build(); final Environment env = randomBoolean() ? new Environment(settings) : null; SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env); @@ -59,15 +64,17 @@ public class SSLBootstrapCheckTests extends ESTestCase { public void testSSLBootstrapCheckWithDefaultKeyBeingUsed() throws Exception { final String keyPrefix = randomBoolean() ? "security.transport." : ""; + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack." + keyPrefix + "ssl.key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient") .put("xpack." + keyPrefix + "ssl.certificate", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) .put("xpack.security.http.ssl.key", getDataPath("/org/elasticsearch/xpack/ssl/private.pem").toString()) .put("xpack.security.http.ssl.certificate", getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) + .setSecureSettings(secureSettings) .build(); final Environment env = randomBoolean() ? new Environment(settings) : null; SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java index 595a3d079d2..dd3baab7b9e 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.network.NetworkModule; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.test.SecurityIntegTestCase; @@ -89,10 +90,12 @@ public class SSLClientAuthTests extends SecurityIntegTestCase { throw new ElasticsearchException("store path doesn't exist"); } + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testclient-client-profile"); Settings settings = Settings.builder() .put("xpack.ssl.client_authentication", SSLClientAuth.NONE) .put("xpack.ssl.keystore.path", store) - .put("xpack.ssl.keystore.password", "testclient-client-profile") + .setSecureSettings(secureSettings) .put("cluster.name", internalCluster().getClusterName()) .put(Security.USER_SETTING.getKey(), transportClientUsername() + ":" + new String(transportClientPassword().getChars())) diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java index ee77aa0a298..5a4a552629a 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ssl; import org.apache.lucene.util.SetOnce; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; @@ -76,10 +77,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase { final Path tempDir = createTempDir(); final Path keystorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); final Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack.ssl.keystore.path", keystorePath) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); final Environment env = randomBoolean() ? null : new Environment(settings); @@ -142,12 +145,14 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"), keyPath); 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); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.secure_key_passphrase", "testnode"); final Settings settings = Settings.builder() .put("path.home", createTempDir()) .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()) + .setSecureSettings(secureSettings) .build(); final Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); @@ -206,10 +211,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path tempDir = createTempDir(); Path trustStorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", trustStorePath) - .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) + .setSecureSettings(secureSettings) .build(); Environment env = randomBoolean() ? null : new Environment(settings); final X500Principal expectedPrincipal = new X500Principal("CN=xpack public development ca"); @@ -301,9 +308,11 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path tempDir = createTempDir(); Path keystorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", keystorePath) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); @@ -339,12 +348,14 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"), keyPath); 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); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.secure_key_passphrase", "testnode"); Settings settings = Settings.builder() .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()) + .setSecureSettings(secureSettings) .build(); Environment env = randomBoolean() ? null : new Environment(settings); final SSLService sslService = new SSLService(settings, env); @@ -374,10 +385,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase { Path tempDir = createTempDir(); Path trustStorePath = tempDir.resolve("testnode.jks"); Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", trustStorePath) - .put("xpack.ssl.truststore.password", "testnode") .put("path.home", createTempDir()) + .setSecureSettings(secureSettings) .build(); Environment env = randomBoolean() ? null : new Environment(settings); final SSLService sslService = new SSLService(settings, env); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java index a5d3a42ea64..935052840f7 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java @@ -9,6 +9,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import java.util.Arrays; +import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; @@ -64,22 +65,6 @@ public class SSLConfigurationSettingsTests extends ESTestCase { assertThat(ssl.supportedProtocols.get(settings), is(Arrays.asList("SSLv3", "SSLv2Hello", "SSLv2"))); } - public void testKeyStoreKeyPasswordDefaultsToKeystorePassword() { - final SSLConfigurationSettings ssl = SSLConfigurationSettings.withPrefix("xpack.ssl."); - - assertThat(ssl.keystorePassword.match("xpack.ssl.keystore.password"), is(true)); - assertThat(ssl.keystoreKeyPassword.match("xpack.ssl.keystore.key_password"), is(true)); - - assertThat(ssl.keystorePassword.match("xpack.ssl.keystore.key_password"), is(false)); - assertThat(ssl.keystoreKeyPassword.match("xpack.ssl.keystore.password"), is(false)); - - final String password = randomAlphaOfLength(16); - final Settings settings = Settings.builder() - .put("xpack.ssl.keystore.password", password) - .build(); - assertThat(ssl.keystoreKeyPassword.get(settings).get(), is(password)); - } - public void testEmptySettingsParsesToDefaults() { final SSLConfigurationSettings ssl = SSLConfigurationSettings.withoutPrefix(); final Settings settings = Settings.EMPTY; @@ -87,15 +72,15 @@ public class SSLConfigurationSettingsTests extends ESTestCase { assertThat(ssl.cert.get(settings).isPresent(), is(false)); assertThat(ssl.ciphers.get(settings).size(), is(0)); assertThat(ssl.clientAuth.get(settings).isPresent(), is(false)); - assertThat(ssl.keyPassword.get(settings).isPresent(), is(false)); + assertThat(ssl.keyPassword.exists(settings), is(false)); assertThat(ssl.keyPath.get(settings).isPresent(), is(false)); assertThat(ssl.keystoreAlgorithm.get(settings), is(KeyManagerFactory.getDefaultAlgorithm())); - assertThat(ssl.keystoreKeyPassword.get(settings).isPresent(), is(false)); - assertThat(ssl.keystorePassword.get(settings).isPresent(), is(false)); + assertThat(ssl.keystoreKeyPassword.exists(settings), is(false)); + assertThat(ssl.keystorePassword.exists(settings), is(false)); assertThat(ssl.keystorePath.get(settings).isPresent(), is(false)); assertThat(ssl.supportedProtocols.get(settings).size(), is(0)); assertThat(ssl.truststoreAlgorithm.get(settings), is(TrustManagerFactory.getDefaultAlgorithm())); - assertThat(ssl.truststorePassword.get(settings).isPresent(), is(false)); + assertThat(ssl.truststorePassword.exists(settings), is(false)); assertThat(ssl.truststorePath.get(settings).isPresent(), is(false)); assertThat(ssl.verificationMode.get(settings).isPresent(), is(false)); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java index 2f72e865499..7cef8b415cd 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java @@ -5,6 +5,8 @@ */ package org.elasticsearch.xpack.ssl; +import org.elasticsearch.common.settings.MockSecureSettings; +import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; @@ -39,9 +41,11 @@ public class SSLConfigurationTests extends ESTestCase { public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() { final String path = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString(); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("keystore.path", path) - .put("keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); // Pass settings in as component settings SSLConfiguration globalSettings = new SSLConfiguration(settings); @@ -61,39 +65,87 @@ public class SSLConfigurationTests extends ESTestCase { } } - public void testThatKeyPasswordCanBeSet() { + public void testKeystorePassword() { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); Settings settings = Settings.builder() - .put("keystore.path", "path") - .put("keystore.password", "password") - .put("keystore.key_password", "key") - .build(); + .put("keystore.path", "path") + .setSecureSettings(secureSettings) + .build(); 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"))); + assertThat(ksKeyInfo.keyPassword, is(equalTo("password"))); } + public void testKeystorePasswordBackcompat() { + Settings settings = Settings.builder() + .put("keystore.path", "path") + .put("keystore.password", "password") + .build(); + 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("password"))); + assertSettingDeprecationsAndWarnings(new Setting[] { + SSLConfiguration.SETTINGS_PARSER.legacyKeystorePassword}); + } + + public void testKeystoreKeyPassword() { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); + secureSettings.setString("keystore.secure_key_password", "keypass"); + Settings settings = Settings.builder() + .put("keystore.path", "path") + .setSecureSettings(secureSettings) + .build(); + 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("keypass"))); + } + + public void testKeystoreKeyPasswordBackcompat() { + Settings settings = Settings.builder() + .put("keystore.path", "path") + .put("keystore.password", "password") + .put("keystore.key_password", "keypass") + .build(); + 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("keypass"))); + assertSettingDeprecationsAndWarnings(new Setting[] { + SSLConfiguration.SETTINGS_PARSER.legacyKeystorePassword, SSLConfiguration.SETTINGS_PARSER.legacyKeystoreKeyPassword}); + } public void testThatProfileSettingsOverrideServiceSettings() { + MockSecureSettings profileSecureSettings = new MockSecureSettings(); + profileSecureSettings.setString("keystore.secure_password", "password"); + profileSecureSettings.setString("keystore.secure_key_password", "key"); + profileSecureSettings.setString("truststore.secure_password", "password for trust"); Settings profileSettings = Settings.builder() .put("keystore.path", "path") - .put("keystore.password", "password") - .put("keystore.key_password", "key") .put("keystore.algorithm", "algo") .put("truststore.path", "trust path") - .put("truststore.password", "password for trust") .put("truststore.algorithm", "trusted") + .setSecureSettings(profileSecureSettings) .build(); + MockSecureSettings serviceSecureSettings = new MockSecureSettings(); + serviceSecureSettings.setString("xpack.ssl.keystore.secure_password", "comp password"); + serviceSecureSettings.setString("xpack.ssl.keystore.secure_key_password", "comp key"); + serviceSecureSettings.setString("xpack.ssl.truststore.secure_password", "comp password for trust"); Settings serviceSettings = Settings.builder() .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") + .setSecureSettings(serviceSecureSettings) .build(); SSLConfiguration globalSettings = new SSLConfiguration(serviceSettings); @@ -128,11 +180,9 @@ public class SSLConfigurationTests extends ESTestCase { public void testThatSettingsWithDifferentKeystoresAreNotEqual() { SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() .put("keystore.path", "path") - .put("keystore.password", randomAlphaOfLength(5)) .build()); SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() .put("keystore.path", "path1") - .put("keystore.password", randomAlphaOfLength(5)) .build()); assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false))); assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false))); @@ -143,11 +193,9 @@ public class SSLConfigurationTests extends ESTestCase { public void testThatSettingsWithDifferentTruststoresAreNotEqual() { SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() .put("truststore.path", "/trust") - .put("truststore.password", randomAlphaOfLength(5)) .build()); SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() .put("truststore.path", "/truststore") - .put("truststore.password", randomAlphaOfLength(5)) .build()); assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false))); assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false))); @@ -167,11 +215,9 @@ public class SSLConfigurationTests extends ESTestCase { public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() { SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() .put("keystore.path", "path") - .put("keystore.password", randomAlphaOfLength(5)) .build()); SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() .put("keystore.path", "path1") - .put("keystore.password", randomAlphaOfLength(5)) .build()); assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode())))); } @@ -179,25 +225,23 @@ public class SSLConfigurationTests extends ESTestCase { public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() { SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder() .put("truststore.path", "/trust") - .put("truststore.password", randomAlphaOfLength(5)) .build()); SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder() .put("truststore.path", "/truststore") - .put("truststore.password", randomAlphaOfLength(5)) .build()); assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode())))); } - public void testConfigurationUsingPEMKeyFiles() { + public void testPEMFile() { Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("secure_key_passphrase", "testnode"); Settings settings = Settings.builder() - .put("key", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) - .put("key_passphrase", "testnode") - .put("certificate", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) - .build(); + .put("key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) + .put("certificate", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .setSecureSettings(secureSettings) + .build(); SSLConfiguration config = new SSLConfiguration(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); @@ -208,19 +252,40 @@ public class SSLConfigurationTests extends ESTestCase { assertCombiningTrustConfigContainsCorrectIssuers(config); } - public void testConfigurationUsingPEMKeyAndTrustFiles() { + public void testPEMFileBackcompat() { + Environment env = randomBoolean() ? null : + new Environment(Settings.builder().put("path.home", createTempDir()).build()); + Settings settings = Settings.builder() + .put("key", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) + .put("key_passphrase", "testnode") + .put("certificate", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .build(); + + 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(), instanceOf(CombiningTrustConfig.class)); + assertCombiningTrustConfigContainsCorrectIssuers(config); + assertSettingDeprecationsAndWarnings(new Setting[] {SSLConfiguration.SETTINGS_PARSER.legacyKeyPassword}); + } + + public void testPEMKeyAndTrustFiles() { Environment env = randomBoolean() ? null : new Environment(Settings.builder().put("path.home", createTempDir()).build()); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("secure_key_passphrase", "testnode"); Settings settings = Settings.builder() - .put("key", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) - .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(); + .put("key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) + .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()) + .setSecureSettings(secureSettings) + .build(); SSLConfiguration config = new SSLConfiguration(settings); assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); @@ -233,6 +298,30 @@ public class SSLConfigurationTests extends ESTestCase { assertNotNull(trustManager); } + public void testPEMKeyAndTrustFilesBackcompat() { + Environment env = randomBoolean() ? null : + new Environment(Settings.builder().put("path.home", createTempDir()).build()); + Settings settings = Settings.builder() + .put("key", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem")) + .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 SSLConfiguration(settings); + assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class)); + PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig(); + KeyManager keyManager = keyConfig.createKeyManager(env); + assertNotNull(keyManager); + assertThat(config.trustConfig(), not(sameInstance(keyConfig))); + assertThat(config.trustConfig(), instanceOf(PEMTrustConfig.class)); + TrustManager trustManager = keyConfig.createTrustManager(env); + assertNotNull(trustManager); + assertSettingDeprecationsAndWarnings(new Setting[] {SSLConfiguration.SETTINGS_PARSER.legacyKeyPassword}); + } + private void assertCombiningTrustConfigContainsCorrectIssuers(SSLConfiguration sslConfiguration) { X509Certificate[] trustConfAcceptedIssuers = sslConfiguration.trustConfig().createTrustManager(null).getAcceptedIssuers(); X509Certificate[] keyConfAcceptedIssuers = sslConfiguration.keyConfig().createTrustManager(null).getAcceptedIssuers(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java index 5b55cae9d3a..0d65968c4db 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java @@ -16,6 +16,7 @@ import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.network.InetAddressHelper; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.util.set.Sets; @@ -70,9 +71,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { Settings.Builder builder = Settings.builder() .put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false)); + + SecuritySettingsSource.addSSLSettingsForStore(builder, + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"); builder.put("resource.reload.interval.high", "1s") - .put(SecuritySettingsSource.getSSLSettingsForStore( - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode")) .put("xpack.ssl.keystore.path", nodeStorePath); if (builder.get("xpack.ssl.truststore.path") != null) { @@ -97,13 +99,14 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { try (OutputStream out = Files.newOutputStream(keystorePath)) { keyStore.store(out, "changeme".toCharArray()); } - + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "changeme"); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack.ssl.keystore.path", keystorePath) - .put("xpack.ssl.keystore.password", "changeme") .put("xpack.ssl.truststore.path", nodeStorePath) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .build(); String node = randomFrom(internalCluster().getNodeNames()); SSLService sslService = new SSLService(settings, new Environment(settings)); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java index 987e55f03c2..79e83a8dfd5 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLServiceTests.java @@ -19,6 +19,7 @@ import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.CheckedRunnable; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; @@ -71,18 +72,21 @@ public class SSLServiceTests extends ESTestCase { public void testThatCustomTruststoreCanBeSpecified() throws Exception { Path testClientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks"); - + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); + secureSettings.setString("transport.profiles.foo.xpack.security.ssl.truststore.secure_password", "testclient"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", testnodeStore) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .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); + MockSecureSettings secureCustomSettings = new MockSecureSettings(); + secureCustomSettings.setString("truststore.secure_password", "testclient"); Settings customTruststoreSettings = Settings.builder() .put("truststore.path", testClientStore) - .put("truststore.password", "testclient") + .setSecureSettings(secureCustomSettings) .build(); SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings, Settings.EMPTY); @@ -93,9 +97,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatSslContextCachingWorks() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); @@ -108,10 +114,12 @@ public class SSLServiceTests extends ESTestCase { public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception { Path differentPasswordsStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); + secureSettings.setString("xpack.ssl.keystore.secure_key_password", "testnode1"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", differentPasswordsStore) - .put("xpack.ssl.keystore.password", "testnode") - .put("xpack.ssl.keystore.key_password", "testnode1") + .setSecureSettings(secureSettings) .build(); new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY); } @@ -120,9 +128,11 @@ public class SSLServiceTests extends ESTestCase { Path differentPasswordsStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks"); try { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", differentPasswordsStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY); fail("expected an exception"); @@ -132,9 +142,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatSSLv3IsNotEnabled() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); @@ -148,9 +160,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testclient"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", testclientStore) - .put("xpack.ssl.truststore.password", "testclient") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); @@ -159,9 +173,11 @@ public class SSLServiceTests extends ESTestCase { public void testCreateWithKeystoreIsValidForServer() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); @@ -169,18 +185,20 @@ public class SSLServiceTests extends ESTestCase { } public void testValidForServerWithFallback() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.truststore.path", testnodeStore) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); assertFalse(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY))); + secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode"); settings = Settings.builder() .put("xpack.ssl.truststore.path", testnodeStore) - .put("xpack.ssl.truststore.password", "testnode") + .setSecureSettings(secureSettings) .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(sslService.sslConfiguration(Settings.EMPTY))); @@ -242,32 +260,36 @@ public class SSLServiceTests extends ESTestCase { } public void testThatTruststorePasswordIsRequired() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .put("xpack.ssl.truststore.path", testnodeStore) .build(); - NullPointerException e = - expectThrows(NullPointerException.class, () -> new SSLService(settings, env)); - assertThat(e.getMessage(), is("truststore password must be specified")); + ElasticsearchException e = + expectThrows(ElasticsearchException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("failed to initialize a TrustManagerFactory")); } public void testThatKeystorePasswordIsRequired() throws Exception { Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) .build(); - NullPointerException e = - expectThrows(NullPointerException.class, () -> new SSLService(settings, env)); - assertThat(e.getMessage(), is("keystore password must be specified")); + ElasticsearchException e = + expectThrows(ElasticsearchException.class, () -> new SSLService(settings, env)); + assertThat(e.getMessage(), is("failed to create trust manager")); } public void testCiphersAndInvalidCiphersWork() throws Exception { List ciphers = new ArrayList<>(XPackSettings.DEFAULT_CIPHERS); ciphers.add("foo"); ciphers.add("bar"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .putArray("xpack.ssl.ciphers", ciphers.toArray(new String[ciphers.size()])) .build(); SSLService sslService = new SSLService(settings, env); @@ -278,9 +300,12 @@ public class SSLServiceTests extends ESTestCase { } public void testInvalidCiphersOnlyThrowsException() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); + Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .putArray("xpack.ssl.cipher_suites", new String[]{"foo", "bar"}) .build(); IllegalArgumentException e = @@ -289,9 +314,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatSSLEngineHasCipherSuitesOrderSet() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); @@ -300,9 +327,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY); @@ -322,9 +351,11 @@ public class SSLServiceTests extends ESTestCase { } public void testThatSSLEngineHasProperCiphersAndProtocols() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testnodeStore) - .put("xpack.ssl.keystore.password", "testnode") + .setSecureSettings(secureSettings) .build(); SSLService sslService = new SSLService(settings, env); SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY); @@ -390,9 +421,11 @@ public class SSLServiceTests extends ESTestCase { @Network public void testThatSSLContextTrustsJDKTrustedCAs() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testclient"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testclientStore) - .put("xpack.ssl.keystore.password", "testclient") + .setSecureSettings(secureSettings) .build(); SSLContext sslContext = new SSLService(settings, env).sslContext(); try (CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build()) { @@ -418,9 +451,11 @@ public class SSLServiceTests extends ESTestCase { @Network public void testThatSSLIOSessionStrategytTrustsJDKTrustedCAs() throws Exception { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("xpack.ssl.keystore.secure_password", "testclient"); Settings settings = Settings.builder() .put("xpack.ssl.keystore.path", testclientStore) - .put("xpack.ssl.keystore.password", "testclient") + .setSecureSettings(secureSettings) .build(); SSLIOSessionStrategy sslStrategy = new SSLService(settings, env).sslIOSessionStrategy(Settings.EMPTY); try (CloseableHttpAsyncClient client = getAsyncHttpClient(sslStrategy)) { diff --git a/qa/full-cluster-restart/build.gradle b/qa/full-cluster-restart/build.gradle index 84addb387ab..136a22360bf 100644 --- a/qa/full-cluster-restart/build.gradle +++ b/qa/full-cluster-restart/build.gradle @@ -152,7 +152,7 @@ subprojects { dataDir = { nodeNum -> oldClusterTest.nodes[nodeNum].dataDir } waitCondition = waitWithAuth setting 'xpack.ssl.keystore.path', 'testnode.jks' - setting 'xpack.ssl.keystore.password', 'testnode' + keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' setting 'xpack.security.authc.realms.native.type', 'native' setting 'xpack.security.authc.realms.native.order', '0' dependsOn copyTestNodeKeystore diff --git a/qa/rolling-upgrade/build.gradle b/qa/rolling-upgrade/build.gradle index 9dc732b6d33..927d5e70427 100644 --- a/qa/rolling-upgrade/build.gradle +++ b/qa/rolling-upgrade/build.gradle @@ -148,7 +148,7 @@ subprojects { dataDir = { nodeNumber -> oldClusterTest.nodes[1].dataDir } waitCondition = waitWithAuth setting 'xpack.ssl.keystore.path', 'testnode.jks' - setting 'xpack.ssl.keystore.password', 'testnode' + keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' setting 'node.attr.upgraded', 'first' dependsOn copyTestNodeKeystore extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks') @@ -176,7 +176,7 @@ subprojects { dataDir = { nodeNumber -> oldClusterTest.nodes[0].dataDir } waitCondition = waitWithAuth setting 'xpack.ssl.keystore.path', 'testnode.jks' - setting 'xpack.ssl.keystore.password', 'testnode' + keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' dependsOn copyTestNodeKeystore extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks') if (withSystemKey) { diff --git a/qa/smoke-test-plugins-ssl/build.gradle b/qa/smoke-test-plugins-ssl/build.gradle index ba403320570..10613161304 100644 --- a/qa/smoke-test-plugins-ssl/build.gradle +++ b/qa/smoke-test-plugins-ssl/build.gradle @@ -172,7 +172,7 @@ integTestCluster { setting 'xpack.security.http.ssl.enabled', 'true' setting 'xpack.security.http.ssl.keystore.path', nodeKeystore.name - setting 'xpack.security.http.ssl.keystore.password', 'keypass' + keystoreSetting 'xpack.security.http.ssl.keystore.secure_password', 'keypass' setting 'xpack.ml.enabled', 'false'