Access SSL contexts using names instead of Settings (#30953)

Historically we have loaded SSL objects (such as SSLContext,
SSLIOSessionStrategy) by passing in the SSL settings, constructing a
new SSL configuration from those settings and then looking for a
cached object that matches those settings.

The primary issue with this approach is that it requires a fully
configured Settings object to be available any time the SSL context
needs to be loaded. If the Settings include SecureSettings (such as
passwords for keys or keystores) then this is not true, and the cached
SSL object cannot be loaded at runtime.

This commit introduces an alternative approach of naming every cached
ssl configuration, so that it is possible to load the SSL context for
a named configuration (such as "xpack.http.ssl"). This means that the
calling code does not need to have ongoing access to the secure
settings that were used to load the configuration.

This change also allows monitoring exporters to use SSL passwords
from secure settings, however an exporter that uses a secure SSL setting
(e.g. truststore.secure_password) may not have its SSL settings updated
dynamically (this is prevented by a settings validator).
Exporters without secure settings can continue to be defined and updated
dynamically.
This commit is contained in:
Tim Vernum 2018-07-13 16:40:09 +10:00 committed by GitHub
parent 332c134517
commit c662565f29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 843 additions and 410 deletions

View File

@ -28,12 +28,12 @@ import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
@ -58,22 +58,9 @@ public class SecurityNetty4Transport extends Netty4Transport {
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
this.sslService = sslService;
this.sslEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
if (sslEnabled) {
this.sslConfiguration = sslService.sslConfiguration(transportSSLSettings, Settings.EMPTY);
Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true);
Map<String, SSLConfiguration> profileConfiguration = new HashMap<>(profileSettingsMap.size() + 1);
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
Settings profileSettings = entry.getValue();
final Settings profileSslSettings = profileSslSettings(profileSettings);
SSLConfiguration configuration = sslService.sslConfiguration(profileSslSettings, transportSSLSettings);
profileConfiguration.put(entry.getKey(), configuration);
}
if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslConfiguration);
}
this.sslConfiguration = sslService.getSSLConfiguration(setting("transport.ssl."));
Map<String, SSLConfiguration> profileConfiguration = getTransportProfileConfigurations(settings, sslService, sslConfiguration);
this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration);
} else {
this.profileConfiguration = Collections.emptyMap();
@ -81,6 +68,21 @@ public class SecurityNetty4Transport extends Netty4Transport {
}
}
public static Map<String, SSLConfiguration> getTransportProfileConfigurations(Settings settings, SSLService sslService,
SSLConfiguration defaultConfiguration) {
Set<String> profileNames = settings.getGroups("transport.profiles.", true).keySet();
Map<String, SSLConfiguration> profileConfiguration = new HashMap<>(profileNames.size() + 1);
for (String profileName : profileNames) {
SSLConfiguration configuration = sslService.getSSLConfiguration("transport.profiles." + profileName + "." + setting("ssl"));
profileConfiguration.put(profileName, configuration);
}
if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, defaultConfiguration);
}
return profileConfiguration;
}
@Override
protected void doStart() {
super.doStart();
@ -209,8 +211,4 @@ public class SecurityNetty4Transport extends Netty4Transport {
super.connect(ctx, remoteAddress, localAddress, promise);
}
}
public static Settings profileSslSettings(Settings profileSettings) {
return profileSettings.getByPrefix(setting("ssl."));
}
}

View File

@ -22,6 +22,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Bridges SSLConfiguration into the {@link Settings} framework, using {@link Setting} objects.
@ -221,4 +223,10 @@ public class SSLConfigurationSettings {
CLIENT_AUTH_SETTING_PROFILES, VERIFICATION_MODE_SETTING_PROFILES);
}
public List<Setting<SecureString>> getSecureSettingsInUse(Settings settings) {
return Stream.of(this.truststorePassword, this.x509KeyPair.keystorePassword,
this.x509KeyPair.keystoreKeyPassword, this.x509KeyPair.keyPassword)
.filter(s -> s.exists(settings))
.collect(Collectors.toList());
}
}

View File

@ -30,7 +30,6 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
@ -49,8 +48,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Provides access to {@link SSLEngine} and {@link SSLSocketFactory} objects based on a provided configuration. All
@ -58,7 +59,23 @@ import java.util.Set;
*/
public class SSLService extends AbstractComponent {
/**
* This is a mapping from "context name" (in general use, the name of a setting key)
* to a configuration.
* This allows us to easily answer the question "What is the configuration for ssl in realm XYZ?"
* Multiple "context names" may map to the same configuration (either by object-identity or by object-equality).
* For example "xpack.http.ssl" may exist as a name in this map and have the global ssl configuration as a value
*/
private final Map<String, SSLConfiguration> sslConfigurations;
/**
* A mapping from a SSLConfiguration to a pre-built context.
* <p>
* This is managed separately to the {@link #sslConfigurations} map, so that a single configuration (by object equality)
* always maps to the same {@link SSLContextHolder}, even if it is being used within a different context-name.
*/
private final Map<SSLConfiguration, SSLContextHolder> sslContexts;
private final SSLConfiguration globalSSLConfiguration;
private final SetOnce<SSLConfiguration> transportSSLConfiguration = new SetOnce<>();
private final Environment env;
@ -71,14 +88,16 @@ public class SSLService extends AbstractComponent {
super(settings);
this.env = environment;
this.globalSSLConfiguration = new SSLConfiguration(settings.getByPrefix(XPackSettings.GLOBAL_SSL_PREFIX));
this.sslConfigurations = new HashMap<>();
this.sslContexts = loadSSLConfigurations();
}
private SSLService(Settings settings, Environment environment, SSLConfiguration globalSSLConfiguration,
Map<SSLConfiguration, SSLContextHolder> sslContexts) {
Map<String, SSLConfiguration> sslConfigurations, Map<SSLConfiguration, SSLContextHolder> sslContexts) {
super(settings);
this.env = environment;
this.globalSSLConfiguration = globalSSLConfiguration;
this.sslConfigurations = sslConfigurations;
this.sslContexts = sslContexts;
}
@ -88,7 +107,7 @@ public class SSLService extends AbstractComponent {
* have been created during initialization
*/
public SSLService createDynamicSSLService() {
return new SSLService(settings, env, globalSSLConfiguration, sslContexts) {
return new SSLService(settings, env, globalSSLConfiguration, sslConfigurations, sslContexts) {
@Override
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
@ -119,9 +138,17 @@ public class SSLService extends AbstractComponent {
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
* a context created from the default configuration
* @return Never {@code null}.
* @deprecated This method will fail if the SSL configuration uses a {@link org.elasticsearch.common.settings.SecureSetting} but the
* {@link org.elasticsearch.common.settings.SecureSettings} have been closed. Use {@link #getSSLConfiguration(String)}
* and {@link #sslIOSessionStrategy(SSLConfiguration)} (Deprecated, but not removed because monitoring uses dynamic SSL settings)
*/
@Deprecated
public SSLIOSessionStrategy sslIOSessionStrategy(Settings settings) {
SSLConfiguration config = sslConfiguration(settings);
return sslIOSessionStrategy(config);
}
public SSLIOSessionStrategy sslIOSessionStrategy(SSLConfiguration config) {
SSLContext sslContext = sslContext(config);
String[] ciphers = supportedCiphers(sslParameters(sslContext).getCipherSuites(), config.cipherSuites(), false);
String[] supportedProtocols = config.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
@ -163,51 +190,15 @@ public class SSLService extends AbstractComponent {
}
/**
* Create a new {@link SSLSocketFactory} based on the provided settings. The settings are used to identify the ssl configuration that
* should be used to create the socket factory. The socket factory will also properly configure the ciphers and protocols on each
* socket that is created
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
* a factory created from the default configuration
* Create a new {@link SSLSocketFactory} based on the provided configuration.
* The socket factory will also properly configure the ciphers and protocols on each socket that is created
* @param configuration The SSL configuration to use. Typically obtained from {@link #getSSLConfiguration(String)}
* @return Never {@code null}.
*/
public SSLSocketFactory sslSocketFactory(Settings settings) {
SSLConfiguration sslConfiguration = sslConfiguration(settings);
SSLSocketFactory socketFactory = sslContext(sslConfiguration).getSocketFactory();
return new SecuritySSLSocketFactory(socketFactory, sslConfiguration.supportedProtocols().toArray(Strings.EMPTY_ARRAY),
supportedCiphers(socketFactory.getSupportedCipherSuites(), sslConfiguration.cipherSuites(), false));
}
/**
* Creates an {@link SSLEngine} based on the provided settings. The settings are used to identify the ssl configuration that should be
* used to create the engine. This SSLEngine cannot be used for hostname verification since the engine will not be created with the
* host and port. This method is useful to obtain an SSLEngine that will be used for server connections or client connections that
* will not use hostname verification.
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
* a SSLEngine created from the default configuration
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
* results in a fallback to the global configuration
* @return {@link SSLEngine}
*/
public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings) {
return createSSLEngine(settings, fallbackSettings, null, -1);
}
/**
* Creates an {@link SSLEngine} based on the provided settings. The settings are used to identify the ssl configuration that should be
* used to create the engine. This SSLEngine can be used for a connection that requires hostname verification assuming the provided
* host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verification enabled
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
* a SSLEngine created from the default configuration
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
* results in a fallback to the global configuration
* @param host the host of the remote endpoint. If using hostname verification, this should match what is in the remote endpoint's
* certificate
* @param port the port of the remote endpoint
* @return {@link SSLEngine}
*/
public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings, String host, int port) {
SSLConfiguration configuration = sslConfiguration(settings, fallbackSettings);
return createSSLEngine(configuration, host, port);
public SSLSocketFactory sslSocketFactory(SSLConfiguration configuration) {
SSLSocketFactory socketFactory = sslContext(configuration).getSocketFactory();
return new SecuritySSLSocketFactory(socketFactory, configuration.supportedProtocols().toArray(Strings.EMPTY_ARRAY),
supportedCiphers(socketFactory.getSupportedCipherSuites(), configuration.cipherSuites(), false));
}
/**
@ -219,7 +210,7 @@ public class SSLService extends AbstractComponent {
* certificate
* @param port the port of the remote endpoint
* @return {@link SSLEngine}
* @see #sslConfiguration(Settings, Settings)
* @see #getSSLConfiguration(String)
*/
public SSLEngine createSSLEngine(SSLConfiguration configuration, String host, int port) {
SSLContext sslContext = sslContext(configuration);
@ -249,47 +240,18 @@ public class SSLService extends AbstractComponent {
* @param sslConfiguration the configuration to check
*/
public boolean isConfigurationValidForServerUsage(SSLConfiguration sslConfiguration) {
Objects.requireNonNull(sslConfiguration, "SSLConfiguration cannot be null");
return sslConfiguration.keyConfig() != KeyConfig.NONE;
}
/**
* Indicates whether client authentication is enabled for a particular configuration
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. The global configuration
* will be used for fallback
*/
public boolean isSSLClientAuthEnabled(Settings settings) {
return isSSLClientAuthEnabled(settings, Settings.EMPTY);
}
/**
* Indicates whether client authentication is enabled for a particular configuration
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix
* @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
* results in a fallback to the global configuration
*/
public boolean isSSLClientAuthEnabled(Settings settings, Settings fallback) {
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
return isSSLClientAuthEnabled(sslConfiguration);
}
/**
* Indicates whether client authentication is enabled for a particular configuration
*/
public boolean isSSLClientAuthEnabled(SSLConfiguration sslConfiguration) {
Objects.requireNonNull(sslConfiguration, "SSLConfiguration cannot be null");
return sslConfiguration.sslClientAuth().enabled();
}
/**
* Returns the {@link VerificationMode} that is specified in the settings (or the default)
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix
* @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
* results in a fallback to the global configuration
*/
public VerificationMode getVerificationMode(Settings settings, Settings fallback) {
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
return sslConfiguration.verificationMode();
}
/**
* Returns the {@link SSLContext} for the global configuration. Mainly used for testing
*/
@ -309,6 +271,7 @@ public class SSLService extends AbstractComponent {
* @throws IllegalArgumentException if not found
*/
SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) {
Objects.requireNonNull(sslConfiguration, "SSL Configuration cannot be null");
SSLContextHolder holder = sslContexts.get(sslConfiguration);
if (holder == null) {
throw new IllegalArgumentException("did not find a SSLContext for [" + sslConfiguration.toString() + "]");
@ -328,20 +291,11 @@ public class SSLService extends AbstractComponent {
return new SSLConfiguration(settings, globalSSLConfiguration);
}
/**
* Returns the existing {@link SSLConfiguration} for the given settings and applies the provided fallback settings instead of the global
* configuration
* @param settings the settings for the ssl configuration
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
* results in a fallback to the global configuration
* @return the ssl configuration for the provided settings. If the settings are empty, the global configuration is returned
*/
public SSLConfiguration sslConfiguration(Settings settings, Settings fallbackSettings) {
if (settings.isEmpty() && fallbackSettings.isEmpty()) {
return globalSSLConfiguration;
}
SSLConfiguration fallback = sslConfiguration(fallbackSettings);
return new SSLConfiguration(settings, fallback);
public Set<String> getTransportProfileContextNames() {
return Collections.unmodifiableSet(this.sslConfigurations
.keySet().stream()
.filter(k -> k.startsWith("transport.profiles."))
.collect(Collectors.toSet()));
}
/**
@ -430,27 +384,46 @@ public class SSLService extends AbstractComponent {
* Parses the settings to load all SSLConfiguration objects that will be used.
*/
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
Map<SSLConfiguration, SSLContextHolder> sslConfigurations = new HashMap<>();
sslConfigurations.put(globalSSLConfiguration, createSslContext(globalSSLConfiguration));
Map<SSLConfiguration, SSLContextHolder> sslContextHolders = new HashMap<>();
sslContextHolders.put(globalSSLConfiguration, createSslContext(globalSSLConfiguration));
this.sslConfigurations.put("xpack.ssl", globalSSLConfiguration);
Map<String, Settings> sslSettingsMap = new HashMap<>();
sslSettingsMap.put(XPackSettings.HTTP_SSL_PREFIX, getHttpTransportSSLSettings(settings));
sslSettingsMap.put("xpack.http.ssl", settings.getByPrefix("xpack.http.ssl."));
sslSettingsMap.putAll(getRealmsSSLSettings(settings));
sslSettingsMap.putAll(getMonitoringExporterSettings(settings));
sslSettingsMap.forEach((key, sslSettings) -> {
if (sslSettings.isEmpty()) {
storeSslConfiguration(key, globalSSLConfiguration);
} else {
final SSLConfiguration configuration = new SSLConfiguration(sslSettings, globalSSLConfiguration);
storeSslConfiguration(key, configuration);
sslContextHolders.computeIfAbsent(configuration, this::createSslContext);
}
});
final Settings transportSSLSettings = settings.getByPrefix(XPackSettings.TRANSPORT_SSL_PREFIX);
List<Settings> sslSettingsList = new ArrayList<>();
sslSettingsList.add(getHttpTransportSSLSettings(settings));
sslSettingsList.add(settings.getByPrefix("xpack.http.ssl."));
sslSettingsList.addAll(getRealmsSSLSettings(settings));
sslSettingsList.addAll(getMonitoringExporterSettings(settings));
sslSettingsList.forEach((sslSettings) ->
sslConfigurations.computeIfAbsent(new SSLConfiguration(sslSettings, globalSSLConfiguration), this::createSslContext));
// transport is special because we want to use a auto-generated key when there isn't one
final SSLConfiguration transportSSLConfiguration = new SSLConfiguration(transportSSLSettings, globalSSLConfiguration);
this.transportSSLConfiguration.set(transportSSLConfiguration);
List<Settings> profileSettings = getTransportProfileSSLSettings(settings);
sslConfigurations.computeIfAbsent(transportSSLConfiguration, this::createSslContext);
profileSettings.forEach((profileSetting) ->
sslConfigurations.computeIfAbsent(new SSLConfiguration(profileSetting, transportSSLConfiguration), this::createSslContext));
return Collections.unmodifiableMap(sslConfigurations);
storeSslConfiguration(XPackSettings.TRANSPORT_SSL_PREFIX, transportSSLConfiguration);
Map<String, Settings> profileSettings = getTransportProfileSSLSettings(settings);
sslContextHolders.computeIfAbsent(transportSSLConfiguration, this::createSslContext);
profileSettings.forEach((key, profileSetting) -> {
final SSLConfiguration configuration = new SSLConfiguration(profileSetting, transportSSLConfiguration);
storeSslConfiguration(key, configuration);
sslContextHolders.computeIfAbsent(configuration, this::createSslContext);
});
return Collections.unmodifiableMap(sslContextHolders);
}
private void storeSslConfiguration(String key, SSLConfiguration configuration) {
if (key.endsWith(".")) {
key = key.substring(0, key.length() - 1);
}
sslConfigurations.put(key, configuration);
}
@ -619,31 +592,32 @@ public class SSLService extends AbstractComponent {
}
}
private static List<Settings> getRealmsSSLSettings(Settings settings) {
List<Settings> sslSettings = new ArrayList<>();
Settings realmsSettings = settings.getByPrefix(SecurityField.setting("authc.realms."));
/**
* @return A map of Settings prefix to Settings object
*/
private static Map<String, Settings> getRealmsSSLSettings(Settings settings) {
Map<String, Settings> sslSettings = new HashMap<>();
final String prefix = SecurityField.setting("authc.realms.");
Settings realmsSettings = settings.getByPrefix(prefix);
for (String name : realmsSettings.names()) {
Settings realmSSLSettings = realmsSettings.getAsSettings(name).getByPrefix("ssl.");
if (realmSSLSettings.isEmpty() == false) {
sslSettings.add(realmSSLSettings);
}
// Put this even if empty, so that the name will be mapped to the global SSL configuration
sslSettings.put(prefix + name + ".ssl", realmSSLSettings);
}
return sslSettings;
}
private static List<Settings> getTransportProfileSSLSettings(Settings settings) {
List<Settings> sslSettings = new ArrayList<>();
private static Map<String, Settings> getTransportProfileSSLSettings(Settings settings) {
Map<String, Settings> sslSettings = new HashMap<>();
Map<String, Settings> profiles = settings.getGroups("transport.profiles.", true);
for (Entry<String, Settings> entry : profiles.entrySet()) {
Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl.");
if (profileSettings.isEmpty() == false) {
sslSettings.add(profileSettings);
}
sslSettings.put("transport.profiles." + entry.getKey() + ".xpack.security.ssl", profileSettings);
}
return sslSettings;
}
public static Settings getHttpTransportSSLSettings(Settings settings) {
private Settings getHttpTransportSSLSettings(Settings settings) {
Settings httpSSLSettings = settings.getByPrefix(XPackSettings.HTTP_SSL_PREFIX);
if (httpSSLSettings.isEmpty()) {
return httpSSLSettings;
@ -656,18 +630,33 @@ public class SSLService extends AbstractComponent {
return builder.build();
}
private static List<Settings> getMonitoringExporterSettings(Settings settings) {
List<Settings> sslSettings = new ArrayList<>();
public SSLConfiguration getHttpTransportSSLConfiguration() {
return getSSLConfiguration(XPackSettings.HTTP_SSL_PREFIX);
}
private static Map<String, Settings> getMonitoringExporterSettings(Settings settings) {
Map<String, Settings> sslSettings = new HashMap<>();
Map<String, Settings> exportersSettings = settings.getGroups("xpack.monitoring.exporters.");
for (Entry<String, Settings> entry : exportersSettings.entrySet()) {
Settings exporterSSLSettings = entry.getValue().getByPrefix("ssl.");
if (exporterSSLSettings.isEmpty() == false) {
sslSettings.add(exporterSSLSettings);
}
// Put this even if empty, so that the name will be mapped to the global SSL configuration
sslSettings.put("xpack.monitoring.exporters." + entry.getKey() + ".ssl", exporterSSLSettings);
}
return sslSettings;
}
public SSLConfiguration getSSLConfiguration(String contextName) {
if (contextName.endsWith(".")) {
contextName = contextName.substring(0, contextName.length() - 1);
}
final SSLConfiguration configuration = sslConfigurations.get(contextName);
if (configuration == null) {
logger.warn("Cannot find SSL configuration for context {}. Known contexts are: {}", contextName,
Strings.collectionToCommaDelimitedString(sslConfigurations.keySet()));
}
return configuration;
}
/**
* Maps the supported protocols to an appropriate ssl context algorithm. We make an attempt to use the "best" algorithm when
* possible. The names in this method are taken from the

View File

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.security.transport.netty4;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.hamcrest.Matchers;
import java.util.Map;
import static org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport.getTransportProfileConfigurations;
public class SecurityNetty4TransportTests extends ESTestCase {
public void testGetTransportProfileConfigurations() {
final Settings settings = Settings.builder()
.put("path.home", createTempDir())
.put("xpack.security.transport.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
.put("transport.profiles.full.xpack.security.ssl.verification_mode", VerificationMode.FULL.name())
.put("transport.profiles.cert.xpack.security.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
.put("transport.profiles.none.xpack.security.ssl.verification_mode", VerificationMode.NONE.name())
.build();
final Environment env = TestEnvironment.newEnvironment(settings);
SSLService sslService = new SSLService(settings, env);
final SSLConfiguration defaultConfig = sslService.getSSLConfiguration("xpack.security.transport.ssl");
final Map<String, SSLConfiguration> profileConfigurations = getTransportProfileConfigurations(settings, sslService, defaultConfig);
assertThat(profileConfigurations.size(), Matchers.equalTo(4));
assertThat(profileConfigurations.keySet(), Matchers.containsInAnyOrder("full", "cert", "none", "default"));
assertThat(profileConfigurations.get("full").verificationMode(), Matchers.equalTo(VerificationMode.FULL));
assertThat(profileConfigurations.get("cert").verificationMode(), Matchers.equalTo(VerificationMode.CERTIFICATE));
assertThat(profileConfigurations.get("none").verificationMode(), Matchers.equalTo(VerificationMode.NONE));
assertThat(profileConfigurations.get("default"), Matchers.sameInstance(defaultConfig));
}
}

View File

@ -303,7 +303,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
.build();
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration config = sslService.getSSLConfiguration("xpack.ssl");
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) {
@Override
void reloadSSLContext(SSLConfiguration configuration) {
@ -344,7 +344,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
.build();
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration config = sslService.getSSLConfiguration("xpack.ssl");
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) {
@Override
void reloadSSLContext(SSLConfiguration configuration) {
@ -379,7 +379,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
.build();
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration config = sslService.getSSLConfiguration("xpack.ssl");
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) {
@Override
void reloadSSLContext(SSLConfiguration configuration) {
@ -411,7 +411,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
.build();
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration config = sslService.getSSLConfiguration("xpack.ssl");
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) {
@Override
void reloadSSLContext(SSLConfiguration configuration) {
@ -440,7 +440,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
final CountDownLatch reloadLatch = new CountDownLatch(1);
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration config = sslService.getSSLConfiguration("xpack.ssl");
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService) {
@Override
void reloadSSLContext(SSLConfiguration configuration) {

View File

@ -38,7 +38,6 @@ import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedActionException;
@ -111,11 +110,18 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureCustomSettings)
.build();
SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings, Settings.EMPTY);
SSLConfiguration configuration = new SSLConfiguration(customTruststoreSettings, globalConfiguration(sslService));
SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(configuration, null, -1);
assertThat(sslEngineWithTruststore, is(not(nullValue())));
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration globalConfig = globalConfiguration(sslService);
SSLEngine sslEngine = sslService.createSSLEngine(globalConfig, null, -1);
assertThat(sslEngineWithTruststore, is(not(sameInstance(sslEngine))));
final SSLConfiguration profileConfiguration = sslService.getSSLConfiguration("transport.profiles.foo.xpack.security.ssl");
assertThat(profileConfiguration, notNullValue());
assertThat(profileConfiguration.trustConfig(), instanceOf(StoreTrustConfig.class));
assertThat(((StoreTrustConfig) profileConfiguration.trustConfig()).trustStorePath, equalTo(testClientStore.toString()));
}
public void testThatSslContextCachingWorks() throws Exception {
@ -132,6 +138,10 @@ public class SSLServiceTests extends ESTestCase {
SSLContext cachedSslContext = sslService.sslContext();
assertThat(sslContext, is(sameInstance(cachedSslContext)));
final SSLConfiguration configuration = sslService.getSSLConfiguration("xpack.ssl");
final SSLContext configContext = sslService.sslContext(configuration);
assertThat(configContext, is(sameInstance(sslContext)));
}
public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception {
@ -144,7 +154,9 @@ public class SSLServiceTests extends ESTestCase {
.put("xpack.ssl.keystore.path", differentPasswordsStore)
.setSecureSettings(secureSettings)
.build();
new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY);
final SSLService sslService = new SSLService(settings, env);
SSLConfiguration configuration = globalConfiguration(sslService);
sslService.createSSLEngine(configuration, null, -1);
}
public void testIncorrectKeyPasswordThrowsException() throws Exception {
@ -157,7 +169,9 @@ public class SSLServiceTests extends ESTestCase {
.put("xpack.ssl.keystore.path", differentPasswordsStore)
.setSecureSettings(secureSettings)
.build();
new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY);
final SSLService sslService = new SSLService(settings, env);
SSLConfiguration configuration = globalConfiguration(sslService);
sslService.createSSLEngine(configuration, null, -1);
fail("expected an exception");
} catch (ElasticsearchException e) {
assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory"));
@ -173,13 +187,15 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine engine = sslService.createSSLEngine(configuration, null, -1);
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
}
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
SSLService sslService = new SSLService(Settings.EMPTY, env);
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine sslEngine = sslService.createSSLEngine(configuration, null, -1);
assertThat(sslEngine, notNullValue());
}
@ -191,7 +207,8 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine sslEngine = sslService.createSSLEngine(configuration, null, -1);
assertThat(sslEngine, notNullValue());
}
@ -206,7 +223,7 @@ public class SSLServiceTests extends ESTestCase {
.build();
SSLService sslService = new SSLService(settings, env);
assertTrue(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY)));
assertTrue(sslService.isConfigurationValidForServerUsage(globalConfiguration(sslService)));
}
public void testValidForServerWithFallback() throws Exception {
@ -218,7 +235,7 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
assertFalse(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY)));
assertFalse(sslService.isConfigurationValidForServerUsage(globalConfiguration(sslService)));
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
settings = Settings.builder()
@ -229,15 +246,13 @@ public class SSLServiceTests extends ESTestCase {
.put("xpack.security.transport.ssl.keystore.type", testnodeStoreType)
.build();
sslService = new SSLService(settings, env);
assertFalse(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY)));
assertTrue(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(
settings.getByPrefix("xpack.security.transport.ssl."))));
assertFalse(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY)));
assertFalse(sslService.isConfigurationValidForServerUsage(globalConfiguration(sslService)));
assertTrue(sslService.isConfigurationValidForServerUsage(sslService.getSSLConfiguration("xpack.security.transport.ssl")));
}
public void testGetVerificationMode() throws Exception {
SSLService sslService = new SSLService(Settings.EMPTY, env);
assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(XPackSettings.VERIFICATION_MODE_DEFAULT));
assertThat(globalConfiguration(sslService).verificationMode(), is(XPackSettings.VERIFICATION_MODE_DEFAULT));
Settings settings = Settings.builder()
.put("xpack.ssl.verification_mode", "none")
@ -245,31 +260,25 @@ public class SSLServiceTests extends ESTestCase {
.put("transport.profiles.foo.xpack.security.ssl.verification_mode", "full")
.build();
sslService = new SSLService(settings, env);
assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(VerificationMode.NONE));
assertThat(sslService.getVerificationMode(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY),
is(VerificationMode.CERTIFICATE));
assertThat(sslService.getVerificationMode(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."),
settings.getByPrefix("xpack.security.transport.ssl.")), is(VerificationMode.FULL));
assertThat(sslService.getVerificationMode(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl.")),
is(VerificationMode.CERTIFICATE));
assertThat(globalConfiguration(sslService).verificationMode(), is(VerificationMode.NONE));
assertThat(sslService.getSSLConfiguration("xpack.security.transport.ssl.").verificationMode(), is(VerificationMode.CERTIFICATE));
assertThat(sslService.getSSLConfiguration("transport.profiles.foo.xpack.security.ssl.").verificationMode(),
is(VerificationMode.FULL));
}
public void testIsSSLClientAuthEnabled() throws Exception {
SSLService sslService = new SSLService(Settings.EMPTY, env);
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY));
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY));
assertTrue(globalConfiguration(sslService).sslClientAuth().enabled());
Settings settings = Settings.builder()
.put("xpack.ssl.client_authentication", "none")
.put("xpack.security.transport.ssl.client_authentication", "optional")
.put("transport.profiles.foo.port", "9400-9410")
.build();
sslService = new SSLService(settings, env);
assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY));
assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY));
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl.")));
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY));
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."),
settings.getByPrefix("xpack.security.transport.ssl.")));
assertFalse(sslService.isSSLClientAuthEnabled(globalConfiguration(sslService)));
assertTrue(sslService.isSSLClientAuthEnabled(sslService.getSSLConfiguration("xpack.security.transport.ssl")));
assertTrue(sslService.isSSLClientAuthEnabled(sslService.getSSLConfiguration("transport.profiles.foo.xpack.security.ssl")));
}
public void testThatHttpClientAuthDefaultsToNone() throws Exception {
@ -279,11 +288,10 @@ public class SSLServiceTests extends ESTestCase {
.build();
final SSLService sslService = new SSLService(globalSettings, env);
final SSLConfiguration globalConfig = sslService.sslConfiguration(Settings.EMPTY);
final SSLConfiguration globalConfig = globalConfiguration(sslService);
assertThat(globalConfig.sslClientAuth(), is(SSLClientAuth.OPTIONAL));
final Settings httpSettings = SSLService.getHttpTransportSSLSettings(globalSettings);
final SSLConfiguration httpConfig = sslService.sslConfiguration(httpSettings);
final SSLConfiguration httpConfig = sslService.getHttpTransportSSLConfiguration();
assertThat(httpConfig.sslClientAuth(), is(SSLClientAuth.NONE));
}
@ -325,7 +333,8 @@ public class SSLServiceTests extends ESTestCase {
.putList("xpack.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
.build();
SSLService sslService = new SSLService(settings, env);
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine engine = sslService.createSSLEngine(configuration, null, -1);
assertThat(engine, is(notNullValue()));
String[] enabledCiphers = engine.getEnabledCipherSuites();
assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar")));
@ -355,7 +364,8 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine engine = sslService.createSSLEngine(configuration, null, -1);
assertThat(engine, is(notNullValue()));
assertTrue(engine.getSSLParameters().getUseCipherSuitesOrder());
}
@ -369,8 +379,8 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY);
SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
SSLConfiguration config = globalConfiguration(sslService);
final SSLSocketFactory factory = sslService.sslSocketFactory(config);
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), config.cipherSuites(), false);
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
@ -394,10 +404,10 @@ public class SSLServiceTests extends ESTestCase {
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
final String[] ciphers = sslService.supportedCiphers(engine.getSupportedCipherSuites(), config.cipherSuites(), false);
final String[] supportedProtocols = config.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
SSLConfiguration configuration = globalConfiguration(sslService);
SSLEngine engine = sslService.createSSLEngine(configuration, null, -1);
final String[] ciphers = sslService.supportedCiphers(engine.getSupportedCipherSuites(), configuration.cipherSuites(), false);
final String[] supportedProtocols = configuration.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
assertThat(engine.getEnabledCipherSuites(), is(ciphers));
assertArrayEquals(ciphers, engine.getSSLParameters().getCipherSuites());
// the order we set the protocols in is not going to be what is returned as internally the JDK may sort the versions
@ -433,6 +443,7 @@ public class SSLServiceTests extends ESTestCase {
// ensure it actually goes through and calls the real method
when(sslService.sslIOSessionStrategy(settings)).thenCallRealMethod();
when(sslService.sslIOSessionStrategy(sslConfig)).thenCallRealMethod();
assertThat(sslService.sslIOSessionStrategy(settings), sameInstance(sslStrategy));
@ -451,7 +462,70 @@ public class SSLServiceTests extends ESTestCase {
assertThat(trustManager.getAcceptedIssuers(), emptyArray());
}
public void testReadCertificateInformation() throws Exception {
public void testGetConfigurationByContextName() throws Exception {
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
final String[] cipherSuites = sslContext.getSupportedSSLParameters().getCipherSuites();
final String[] contextNames = {
"xpack.ssl",
"xpack.http.ssl",
"xpack.security.http.ssl",
"xpack.security.transport.ssl",
"transport.profiles.prof1.xpack.security.ssl",
"transport.profiles.prof2.xpack.security.ssl",
"transport.profiles.prof3.xpack.security.ssl",
"xpack.security.authc.realms.realm1.ssl",
"xpack.security.authc.realms.realm2.ssl",
"xpack.monitoring.exporters.mon1.ssl",
"xpack.monitoring.exporters.mon2.ssl"
};
assumeTrue("Not enough cipher suites are available to support this test", cipherSuites.length >= contextNames.length);
// Here we use a different ciphers for each context, so we can check that the returned SSLConfiguration matches the
// provided settings
final Iterator<String> cipher = Arrays.asList(cipherSuites).iterator();
final MockSecureSettings secureSettings = new MockSecureSettings();
final Settings.Builder builder = Settings.builder();
for (String prefix : contextNames) {
secureSettings.setString(prefix + ".keystore.secure_password", "testnode");
builder.put(prefix + ".keystore.path", testnodeStore)
.putList(prefix + ".cipher_suites", cipher.next());
}
final Settings settings = builder
// Add a realm without SSL settings. This context name should be mapped to the global configuration
.put("xpack.security.authc.realms.realm3.type", "file")
// Add an exporter without SSL settings. This context name should be mapped to the global configuration
.put("xpack.monitoring.exporters.mon3.type", "http")
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
for (int i = 0; i < contextNames.length; i++) {
final String name = contextNames[i];
final SSLConfiguration configuration = sslService.getSSLConfiguration(name);
assertThat("Configuration for " + name, configuration, notNullValue());
assertThat("KeyStore for " + name, configuration.keyConfig(), instanceOf(StoreKeyConfig.class));
final StoreKeyConfig keyConfig = (StoreKeyConfig) configuration.keyConfig();
assertThat("KeyStore Path for " + name, keyConfig.keyStorePath, equalTo(testnodeStore.toString()));
assertThat("Cipher for " + name, configuration.cipherSuites(), contains(cipherSuites[i]));
assertThat("Configuration for " + name + ".", sslService.getSSLConfiguration(name + "."), sameInstance(configuration));
}
// These contexts have no SSL settings, but for convenience we want those components to be able to access their context
// by name, and get back the global configuration
final SSLConfiguration realm3Config = sslService.getSSLConfiguration("xpack.security.authc.realms.realm3.ssl");
final SSLConfiguration mon3Config = sslService.getSSLConfiguration("xpack.monitoring.exporters.mon3.ssl.");
final SSLConfiguration global = globalConfiguration(sslService);
assertThat(realm3Config, sameInstance(global));
assertThat(mon3Config, sameInstance(global));
}
public void testReadCertificateInformation () throws Exception {
final Path jksPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
final Path p12Path = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
final Path pemPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt");
@ -601,7 +675,9 @@ public class SSLServiceTests extends ESTestCase {
@Network
public void testThatSSLIOSessionStrategyWithoutSettingsWorks() throws Exception {
SSLService sslService = new SSLService(Settings.EMPTY, env);
SSLIOSessionStrategy sslStrategy = sslService.sslIOSessionStrategy(Settings.EMPTY);
SSLConfiguration sslConfiguration = globalConfiguration(sslService);
logger.info("SSL Configuration: {}", sslConfiguration);
SSLIOSessionStrategy sslStrategy = sslService.sslIOSessionStrategy(sslConfiguration);
try (CloseableHttpAsyncClient client = getAsyncHttpClient(sslStrategy)) {
client.start();
@ -613,14 +689,15 @@ public class SSLServiceTests extends ESTestCase {
}
@Network
public void testThatSSLIOSessionStrategytTrustsJDKTrustedCAs() throws Exception {
public void testThatSSLIOSessionStrategyTrustsJDKTrustedCAs() throws Exception {
MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.ssl.keystore.secure_password", "testclient");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testclientStore)
.setSecureSettings(secureSettings)
.build();
SSLIOSessionStrategy sslStrategy = new SSLService(settings, env).sslIOSessionStrategy(Settings.EMPTY);
final SSLService sslService = new SSLService(settings, env);
SSLIOSessionStrategy sslStrategy = sslService.sslIOSessionStrategy(globalConfiguration(sslService));
try (CloseableHttpAsyncClient client = getAsyncHttpClient(sslStrategy)) {
client.start();
@ -630,6 +707,10 @@ public class SSLServiceTests extends ESTestCase {
}
}
private static SSLConfiguration globalConfiguration(SSLService sslService) {
return sslService.getSSLConfiguration("xpack.ssl");
}
class AssertionCallback implements FutureCallback<HttpResponse> {
@Override

View File

@ -55,6 +55,7 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
this.licenseState = Objects.requireNonNull(licenseState);
clusterService.getClusterSettings().addSettingsUpdateConsumer(this::setExportersSetting, getSettings());
HttpExporter.registerSettingValidators(clusterService);
// this ensures, that logging is happening by adding an empty consumer per affix setting
for (Setting.AffixSetting<?> affixSetting : getSettings()) {
clusterService.getClusterSettings().addAffixUpdateConsumer(affixSetting, (s, o) -> {}, (s, o) -> {});

View File

@ -34,6 +34,8 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.xpack.core.monitoring.exporter.MonitoringTemplateUtils;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.monitoring.exporter.ClusterAlertsUtil;
import org.elasticsearch.xpack.monitoring.exporter.Exporter;
@ -50,6 +52,7 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* {@code HttpExporter} uses the low-level {@link RestClient} to connect to a user-specified set of nodes for exporting Monitoring
@ -252,6 +255,30 @@ public class HttpExporter extends Exporter {
listener.setResource(resource);
}
/**
* Adds a validator for the {@link #SSL_SETTING} to prevent dynamic updates when secure settings also exist within that setting
* groups (ssl context).
* Because it is not possible to re-read the secure settings during a dynamic update, we cannot rebuild the {@link SSLIOSessionStrategy}
* (see {@link #configureSecurity(RestClientBuilder, Config, SSLService)} if this exporter has been configured with secure settings
*/
public static void registerSettingValidators(ClusterService clusterService) {
clusterService.getClusterSettings().addAffixUpdateConsumer(SSL_SETTING,
(ignoreKey, ignoreSettings) -> {
// no-op update. We only care about the validator
},
(namespace, settings) -> {
final List<String> secureSettings = SSLConfigurationSettings.withoutPrefix()
.getSecureSettingsInUse(settings)
.stream()
.map(Setting::getKey)
.collect(Collectors.toList());
if (secureSettings.isEmpty() == false) {
throw new IllegalStateException("Cannot dynamically update SSL settings for the exporter [" + namespace
+ "] as it depends on the secure setting(s) [" + Strings.collectionToCommaDelimitedString(secureSettings) + "]");
}
});
}
/**
* Create a {@link RestClientBuilder} from the HTTP Exporter's {@code config}.
*
@ -443,8 +470,20 @@ public class HttpExporter extends Exporter {
* @throws SettingsException if any setting causes issues
*/
private static void configureSecurity(final RestClientBuilder builder, final Config config, final SSLService sslService) {
final Settings sslSettings = SSL_SETTING.getConcreteSettingForNamespace(config.name()).get(config.settings());
final SSLIOSessionStrategy sslStrategy = sslService.sslIOSessionStrategy(sslSettings);
final Setting<Settings> concreteSetting = SSL_SETTING.getConcreteSettingForNamespace(config.name());
final Settings sslSettings = concreteSetting.get(config.settings());
final SSLIOSessionStrategy sslStrategy;
if (SSLConfigurationSettings.withoutPrefix().getSecureSettingsInUse(sslSettings).isEmpty()) {
// This configuration does not use secure settings, so it is possible that is has been dynamically updated.
// We need to load a new SSL strategy in case these settings differ from the ones that the SSL service was configured with.
sslStrategy = sslService.sslIOSessionStrategy(sslSettings);
} else {
// This configuration uses secure settings. We cannot load a new SSL strategy, as the secure settings have already been closed.
// Due to #registerSettingValidators we know that the settings not been dynamically updated, and the pre-configured strategy
// is still the correct configuration for use in this exporter.
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(concreteSetting.getKey());
sslStrategy = sslService.sslIOSessionStrategy(sslConfiguration);
}
final CredentialsProvider credentialsProvider = createCredentialsProvider(config);
List<String> hostList = HOST_SETTING.getConcreteSettingForNamespace(config.name()).get(config.settings());
// sending credentials in plaintext!

View File

@ -0,0 +1,188 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.monitoring.exporter.http;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.elasticsearch.test.http.MockWebServer;
import org.elasticsearch.xpack.core.ssl.TestsSSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.elasticsearch.xpack.monitoring.exporter.Exporter;
import org.elasticsearch.xpack.monitoring.exporter.Exporters;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import org.hamcrest.CoreMatchers;
import org.junit.AfterClass;
import org.junit.Before;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.notNullValue;
@ESIntegTestCase.ClusterScope(scope = Scope.SUITE,
numDataNodes = 1, numClientNodes = 0, transportClientRatio = 0.0, supportsDedicatedMasters = false)
public class HttpExporterSslIT extends MonitoringIntegTestCase {
private final Settings globalSettings = Settings.builder().put("path.home", createTempDir()).build();
private final Environment environment = TestEnvironment.newEnvironment(globalSettings);
private static MockWebServer webServer;
private MockSecureSettings secureSettings;
@AfterClass
public static void cleanUpStatics() {
if (webServer != null) {
webServer.close();
webServer = null;
}
}
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
final Path truststore = getDataPath("/org/elasticsearch/xpack/monitoring/exporter/http/testnode.jks");
assertThat(Files.exists(truststore), CoreMatchers.is(true));
if (webServer == null) {
try {
webServer = buildWebServer();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
final String address = "https://" + webServer.getHostName() + ":" + webServer.getPort();
final Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put("xpack.monitoring.exporters.plaintext.type", "http")
.put("xpack.monitoring.exporters.plaintext.enabled", true)
.put("xpack.monitoring.exporters.plaintext.host", address)
.put("xpack.monitoring.exporters.plaintext.ssl.truststore.path", truststore)
.put("xpack.monitoring.exporters.plaintext.ssl.truststore.password", "testnode")
.put("xpack.monitoring.exporters.secure.type", "http")
.put("xpack.monitoring.exporters.secure.enabled", true)
.put("xpack.monitoring.exporters.secure.host", address)
.put("xpack.monitoring.exporters.secure.ssl.truststore.path", truststore);
secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.monitoring.exporters.secure.ssl.truststore.secure_password", "testnode");
builder.setSecureSettings(secureSettings);
return builder.build();
}
private MockWebServer buildWebServer() throws IOException {
final Path cert = getDataPath("/org/elasticsearch/xpack/monitoring/exporter/http/testnode.crt");
final Path key = getDataPath("/org/elasticsearch/xpack/monitoring/exporter/http/testnode.pem");
final Settings sslSettings = Settings.builder()
.put("xpack.ssl.certificate", cert)
.put("xpack.ssl.key", key)
.put("xpack.ssl.key_passphrase", "testnode")
.put(globalSettings)
.build();
TestsSSLService sslService = new TestsSSLService(sslSettings, environment);
final SSLContext sslContext = sslService.sslContext(Settings.EMPTY);
MockWebServer server = new MockWebServer(sslContext, false);
server.start();
return server;
}
@Before
// Force the exporters to be built from closed secure settings (as they would be in a production environment)
public void closeSecureSettings() throws IOException {
if (secureSettings != null) {
secureSettings.close();
}
}
public void testCannotUpdateSslSettingsWithSecureSettings() throws Exception {
// Verify that it was created even though it has a secure setting
assertExporterExists("secure");
// Verify that we cannot modify the SSL settings
final ActionFuture<ClusterUpdateSettingsResponse> future = setVerificationMode("secure", VerificationMode.CERTIFICATE);
final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, future::actionGet);
assertThat(iae.getCause(), instanceOf(IllegalStateException.class));
assertThat(iae.getCause().getMessage(), containsString("secure_password"));
}
public void testCanUpdateSslSettingsWithNoSecureSettings() {
final ActionFuture<ClusterUpdateSettingsResponse> future = setVerificationMode("plaintext", VerificationMode.CERTIFICATE);
final ClusterUpdateSettingsResponse response = future.actionGet();
assertThat(response, notNullValue());
clearTransientSettings("plaintext");
}
public void testCanAddNewExporterWithSsl() {
Path truststore = getDataPath("/org/elasticsearch/xpack/monitoring/exporter/http/testnode.jks");
assertThat(Files.exists(truststore), CoreMatchers.is(true));
final ClusterUpdateSettingsRequest updateSettings = new ClusterUpdateSettingsRequest();
final Settings settings = Settings.builder()
.put("xpack.monitoring.exporters._new.type", "http")
.put("xpack.monitoring.exporters._new.host", "https://" + webServer.getHostName() + ":" + webServer.getPort())
.put("xpack.monitoring.exporters._new.ssl.truststore.path", truststore)
.put("xpack.monitoring.exporters._new.ssl.truststore.password", "testnode")
.put("xpack.monitoring.exporters._new.ssl.verification_mode", VerificationMode.NONE.name())
.build();
updateSettings.transientSettings(settings);
final ActionFuture<ClusterUpdateSettingsResponse> future = client().admin().cluster().updateSettings(updateSettings);
final ClusterUpdateSettingsResponse response = future.actionGet();
assertThat(response, notNullValue());
assertExporterExists("_new");
clearTransientSettings("_new");
}
private void assertExporterExists(String secure) {
final Exporter httpExporter = getExporter(secure);
assertThat(httpExporter, notNullValue());
assertThat(httpExporter, instanceOf(HttpExporter.class));
}
private Exporter getExporter(String name) {
final Exporters exporters = internalCluster().getInstance(Exporters.class);
assertThat(exporters, notNullValue());
return exporters.getExporter(name);
}
private ActionFuture<ClusterUpdateSettingsResponse> setVerificationMode(String name, VerificationMode mode) {
final ClusterUpdateSettingsRequest updateSettings = new ClusterUpdateSettingsRequest();
final Settings settings = Settings.builder()
.put("xpack.monitoring.exporters." + name + ".ssl.verification_mode", mode.name())
.build();
updateSettings.transientSettings(settings);
return client().admin().cluster().updateSettings(updateSettings);
}
private void clearTransientSettings(String... names) {
final ClusterUpdateSettingsRequest updateSettings = new ClusterUpdateSettingsRequest();
final Settings.Builder builder = Settings.builder();
for (String name : names) {
builder.put("xpack.monitoring.exporters." + name + ".*", (String) null);
}
updateSettings.transientSettings(builder.build());
client().admin().cluster().updateSettings(updateSettings).actionGet();
}
}

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID0zCCArugAwIBAgIJALi5bDfjMszLMA0GCSqGSIb3DQEBCwUAMEgxDDAKBgNV
BAoTA29yZzEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEgMB4GA1UEAxMXRWxhc3Rp
Y3NlYXJjaCBUZXN0IE5vZGUwHhcNMTUwOTIzMTg1MjU3WhcNMTkwOTIyMTg1MjU3
WjBIMQwwCgYDVQQKEwNvcmcxFjAUBgNVBAsTDWVsYXN0aWNzZWFyY2gxIDAeBgNV
BAMTF0VsYXN0aWNzZWFyY2ggVGVzdCBOb2RlMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA3rGZ1QbsW0+MuyrSLmMfDFKtLBkIFW8V0gRuurFg1PUKKNR1
Mq2tMVwjjYETAU/UY0iKZOzjgvYPKhDTYBTte/WHR1ZK4CYVv7TQX/gtFQG/ge/c
7u0sLch9p7fbd+/HZiLS/rBEZDIohvgUvzvnA8+OIYnw4kuxKo/5iboAIS41klMg
/lATm8V71LMY68inht71/ZkQoAHKgcR9z4yNYvQ1WqKG8DG8KROXltll3sTrKbl5
zJhn660es/1ZnR6nvwt6xnSTl/mNHMjkfv1bs4rJ/py3qPxicdoSIn/KyojUcgHV
F38fuAy2CQTdjVG5fWj9iz+mQvLm3+qsIYQdFwIDAQABo4G/MIG8MAkGA1UdEwQC
MAAwHQYDVR0OBBYEFEMMWLWQi/g83PzlHYqAVnty5L7HMIGPBgNVHREEgYcwgYSC
CWxvY2FsaG9zdIIVbG9jYWxob3N0LmxvY2FsZG9tYWluggpsb2NhbGhvc3Q0ghds
b2NhbGhvc3Q0LmxvY2FsZG9tYWluNIIKbG9jYWxob3N0NoIXbG9jYWxob3N0Ni5s
b2NhbGRvbWFpbjaHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL
BQADggEBAMjGGXT8Nt1tbl2GkiKtmiuGE2Ej66YuZ37WSJViaRNDVHLlg87TCcHe
k2rdO+6sFqQbbzEfwQ05T7xGmVu7tm54HwKMRugoQ3wct0bQC5wEWYN+oMDvSyO6
M28mZwWb4VtR2IRyWP+ve5DHwTM9mxWa6rBlGzsQqH6YkJpZojzqk/mQTug+Y8aE
mVoqRIPMHq9ob+S9qd5lp09+MtYpwPfTPx/NN+xMEooXWW/ARfpGhWPkg/FuCu4z
1tFmCqHgNcWirzMm3dQpF78muE9ng6OB2MXQwL4VgnVkxmlZNHbkR2v/t8MyZJxC
y4g6cTMM3S/UMt5/+aIB2JAuMKyuD+A=
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,9D867F7E0C94D013
dVoVCjPeg1wgS7rVtOvGfQcrZyLkx393aWRnFq45tbjKBVuITtJ9vI7o4QXOV/15
Gnb6WhXGIdWrzsxEAd46K6hIuNSISd4Emsx6c2Q5hTqWXXfexbOZBNfTtXtdJPnJ
1jAaikhtztLo3JSLTKNY5sNxd+XbaQyYVUWvueK6zOaIIMETvB+VPVFd9i1ROibk
Sgdtyj01KjkoalifqK/tA0CIYNKL0S6/eoK3UhAlpIprlpV+cnXa940C6bjLeJPt
PMAGGp5RrplxSgrSerw3I9DOWkHGtpqzIka3XneNUXJP8k4HUJ+aZkGH2ZILKS8d
4KMIb+KZSpHEGn+6uGccWLtZZmAjWJrDw56JbQtSHdRYLBRSOjLbTvQoPu/2Hpli
7HOxbotlvjptMunncq5aqK57SHA1dh0cwF7J3LUmGFJ67eoz+VV3b5qMn4MopSeI
mS16Ydd3nGpjSrln/elM0CQxqWfcOAXRZpDpFUQoXcBrLVzvz2DBl/0CrTRLhgzi
CO+5/IVcBWRlYpRNGgjjP7q0j6URID3jk5J06fYQXmBiwQT5j+GZqqzpMCJ9mIy2
1O9SN1hebJnIcEU+E0njn/MGjlYdPywhaCy8pqElp6Q8TUEJpwLRFO/owCoBet/n
ZmCXUjfCGhc1pWHufFcDEQ6xMgEWWY/tdwCZeSU7EhErTjCbfupg+55A5fpDml0m
3wH4CFcuRjlqyx6Ywixm1ATeitDtJl5HQTw6b8OtEXwSgRmZ0eSqSRVk9QbVS7gu
IpQe09/Zimb5HzjZqZ3fdqHlcW4xax8hyJeyIvF5ZJ57eY8CBvu/wP2GDn26QnvF
xQqdfDbq1H4JmpwUHpbFwBoQK4Q6WFd1z4EA9bRQeo3H9PoqoOwMDjzajwLRF7b7
q6tYH/n9PyHwdf1c4fFwgSmL1toXGfKlA9hjIaLsRSDD6srT5EdUk78bsnddwI51
tu7C7P4JG+h1VdRNMNTlqtileWsIE7Nn2A1OkcUxZdF5mamENpDpJcHePLto6c8q
FKiwyFMsxhgsj6HK2HqO+UA4sX5Ni4oHwiPmb//EZLn045M5i1AN26KosJmb8++D
sgR5reWRy+UqJCTYblVg+7Dx++ggUnfxVyQEsWmw5r5f4KU5wXBkvoVMGtPNa9DE
n/uLtObD1qkNL38pRsr2OGRchYCgEoKGqEISBP4knfGXLOlWiW/246j9QzI97r1u
tvy7fKg28G7AUz9l6bpewsPHefBUeRQeieP9eJINaEpxkF/w2RpKDLpQjWxwDDOM
s+D0mrBMJve17AmJ8rMw6dIQPZYNZ88/jz1uQuUwQ2YlbmtZbCG81k9YMFGEU9XS
cyhJxj8hvYnt2PR5Z9/cJPyWOs0m/ufOeeQQ8SnU/lzmrQnpzUd2Z6p5i/B7LdRP
n1kX+l1qynuPnjvBz4nJQE0p6nzW8RyCDSniC9mtYtZmhgC8icqxgbvS7uEOBIYJ
NbK+0bEETTO34iY/JVTIqLOw3iQZYMeUpxpj6Phgx/oooxMTquMecPKNgeVtaBst
qjTNPX0ti1/HYpZqzYi8SV8YjHSJWCVMsZjKPr3W/HIcCKqYoIfgzi83Ha2KMQx6
-----END RSA PRIVATE KEY-----

View File

@ -11,7 +11,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
@ -24,34 +23,9 @@ import static org.elasticsearch.xpack.core.security.SecurityField.setting;
class PkiRealmBootstrapCheck implements BootstrapCheck {
private final SSLService sslService;
private final List<SSLConfiguration> sslConfigurations;
PkiRealmBootstrapCheck(Settings settings, SSLService sslService) {
PkiRealmBootstrapCheck(SSLService sslService) {
this.sslService = sslService;
this.sslConfigurations = loadSslConfigurations(settings);
}
/**
* {@link SSLConfiguration} may depend on {@link org.elasticsearch.common.settings.SecureSettings} that can only be read during startup.
* We need to preload these during component configuration.
*/
private List<SSLConfiguration> loadSslConfigurations(Settings settings) {
final List<SSLConfiguration> list = new ArrayList<>();
if (HTTP_SSL_ENABLED.get(settings)) {
list.add(sslService.sslConfiguration(SSLService.getHttpTransportSSLSettings(settings), Settings.EMPTY));
}
if (XPackSettings.TRANSPORT_SSL_ENABLED.get(settings)) {
final Settings transportSslSettings = settings.getByPrefix(setting("transport.ssl."));
list.add(sslService.sslConfiguration(transportSslSettings, Settings.EMPTY));
settings.getGroups("transport.profiles.").values().stream()
.map(SecurityNetty4Transport::profileSslSettings)
.map(s -> sslService.sslConfiguration(s, transportSslSettings))
.forEach(list::add);
}
return list;
}
/**
@ -65,7 +39,8 @@ class PkiRealmBootstrapCheck implements BootstrapCheck {
.filter(s -> PkiRealmSettings.TYPE.equals(s.get("type")))
.anyMatch(s -> s.getAsBoolean("enabled", true));
if (pkiRealmEnabled) {
for (SSLConfiguration configuration : this.sslConfigurations) {
for (String contextName : getSslContextNames(settings)) {
final SSLConfiguration configuration = sslService.getSSLConfiguration(contextName);
if (sslService.isSSLClientAuthEnabled(configuration)) {
return BootstrapCheckResult.success();
}
@ -77,6 +52,20 @@ class PkiRealmBootstrapCheck implements BootstrapCheck {
}
}
private List<String> getSslContextNames(Settings settings) {
final List<String> list = new ArrayList<>();
if (HTTP_SSL_ENABLED.get(settings)) {
list.add(setting("http.ssl"));
}
if (XPackSettings.TRANSPORT_SSL_ENABLED.get(settings)) {
list.add(setting("transport.ssl"));
list.addAll(sslService.getTransportProfileContextNames());
}
return list;
}
@Override
public boolean alwaysEnforce() {
return true;

View File

@ -117,16 +117,17 @@ import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessCo
import org.elasticsearch.xpack.core.security.authz.accesscontrol.SecurityIndexSearcherWrapper;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsCache;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.core.security.index.IndexAuditTrailField;
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.TLSLicenseBootstrapCheck;
import org.elasticsearch.xpack.core.ssl.action.GetCertificateInfoAction;
import org.elasticsearch.xpack.core.ssl.action.TransportGetCertificateInfoAction;
import org.elasticsearch.xpack.core.ssl.rest.RestGetCertificateInfoAction;
import org.elasticsearch.xpack.core.template.TemplateUtils;
import org.elasticsearch.xpack.security.action.filter.SecurityActionFilter;
import org.elasticsearch.xpack.security.action.interceptor.BulkShardRequestInterceptor;
import org.elasticsearch.xpack.security.action.interceptor.IndicesAliasesRequestInterceptor;
@ -172,6 +173,7 @@ import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.SecuritySearchOperationListener;
import org.elasticsearch.xpack.security.authz.accesscontrol.OptOutQueryCache;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.ingest.HashProcessor;
import org.elasticsearch.xpack.security.ingest.SetSecurityUserProcessor;
@ -232,9 +234,9 @@ import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin,
DiscoveryPlugin, MapperPlugin, ExtensiblePlugin {
@ -286,7 +288,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
final List<BootstrapCheck> checks = new ArrayList<>();
checks.addAll(Arrays.asList(
new TokenSSLBootstrapCheck(),
new PkiRealmBootstrapCheck(settings, getSslService()),
new PkiRealmBootstrapCheck(getSslService()),
new TLSLicenseBootstrapCheck(),
new PasswordHashingAlgorithmBootstrapCheck()));
checks.addAll(InternalRealms.getBootstrapChecks(settings, env));
@ -877,10 +879,9 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
return null;
}
final boolean ssl = HTTP_SSL_ENABLED.get(settings);
Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings);
boolean extractClientCertificate = ssl && getSslService().isSSLClientAuthEnabled(httpSSLSettings);
return handler -> new SecurityRestFilter(getLicenseState(), threadContext, authcService.get(), handler,
extractClientCertificate);
final SSLConfiguration httpSSLConfig = getSslService().getHttpTransportSSLConfiguration();
boolean extractClientCertificate = ssl && getSslService().isSSLClientAuthEnabled(httpSSLConfig);
return handler -> new SecurityRestFilter(getLicenseState(), threadContext, authcService.get(), handler, extractClientCertificate);
}
@Override

View File

@ -41,6 +41,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.security.authc.file.FileUserPasswdStore;
@ -148,12 +149,12 @@ public class ESNativeRealmMigrateTool extends LoggingAwareMultiCommand {
HttpURLConnection conn;
// If using SSL, need a custom service because it's likely a self-signed certificate
if ("https".equalsIgnoreCase(uri.getScheme())) {
Settings sslSettings = settings.getByPrefix(setting("http.ssl."));
final SSLService sslService = new SSLService(settings, env);
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(setting("http.ssl"));
final HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
// Requires permission java.lang.RuntimePermission "setFactory";
httpsConn.setSSLSocketFactory(sslService.sslSocketFactory(sslSettings));
httpsConn.setSSLSocketFactory(sslService.sslSocketFactory(sslConfiguration));
return null;
});
conn = httpsConn;

View File

@ -19,9 +19,11 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.security.authc.esnative.tool.HttpResponse.HttpResponseBuilder;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -35,8 +37,6 @@ import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_PORT;
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_PUBLISH_HOST;
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_PUBLISH_PORT;
@ -86,11 +86,10 @@ public class CommandLineHttpClient {
final SSLService sslService = new SSLService(settings, env);
final HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
final Settings sslSettings = SSLService.getHttpTransportSSLSettings(settings);
final SSLConfiguration sslConfiguration = sslService.getHttpTransportSSLConfiguration();
// Requires permission java.lang.RuntimePermission "setFactory";
httpsConn.setSSLSocketFactory(sslService.sslSocketFactory(sslSettings));
final boolean isHostnameVerificationEnabled =
sslService.getVerificationMode(sslSettings, Settings.EMPTY).isHostnameVerificationEnabled();
httpsConn.setSSLSocketFactory(sslService.sslSocketFactory(sslConfiguration));
final boolean isHostnameVerificationEnabled = sslConfiguration.verificationMode().isHostnameVerificationEnabled();
if (isHostnameVerificationEnabled == false) {
httpsConn.setHostnameVerifier((hostname, session) -> true);
}

View File

@ -21,12 +21,11 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import javax.net.SocketFactory;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
@ -133,20 +132,23 @@ public abstract class SessionFactory {
final Settings realmSSLSettings = realmSettings.getByPrefix("ssl.");
final boolean verificationModeExists =
sslConfigurationSettings.verificationMode.exists(realmSSLSettings);
final boolean hostnameVerficationExists =
final boolean hostnameVerificationExists =
realmSettings.get(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, null) != null;
if (verificationModeExists && hostnameVerficationExists) {
if (verificationModeExists && hostnameVerificationExists) {
throw new IllegalArgumentException("[" + SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING + "] and [" +
sslConfigurationSettings.verificationMode.getKey() +
"] may not be used at the same time");
} else if (verificationModeExists) {
VerificationMode verificationMode = sslService.getVerificationMode(realmSSLSettings,
Settings.EMPTY);
if (verificationMode == VerificationMode.FULL) {
final String sslKey = RealmSettings.getFullSettingKey(config, "ssl");
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(sslKey);
if (sslConfiguration == null) {
throw new IllegalStateException("cannot find SSL configuration for " + sslKey);
}
if (sslConfiguration.verificationMode().isHostnameVerificationEnabled()) {
options.setSSLSocketVerifier(new HostNameSSLSocketVerifier(true));
}
} else if (hostnameVerficationExists) {
} else if (hostnameVerificationExists) {
new DeprecationLogger(logger).deprecated("the setting [{}] has been deprecated and " +
"will be removed in a future version. use [{}] instead",
RealmSettings.getFullSettingKey(config, SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING),
@ -180,7 +182,8 @@ public abstract class SessionFactory {
Settings settings = realmConfig.settings();
SocketFactory socketFactory = null;
if (ldapServers.ssl()) {
socketFactory = clientSSLService.sslSocketFactory(settings.getByPrefix("ssl."));
SSLConfiguration ssl = clientSSLService.getSSLConfiguration(RealmSettings.getFullSettingKey(realmConfig, "ssl"));
socketFactory = clientSSLService.sslSocketFactory(ssl);
if (settings.getAsBoolean(SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING, true)) {
logger.debug("using encryption for LDAP connections with hostname verification");
} else {

View File

@ -44,6 +44,7 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.X509KeyPairSettings;
@ -498,10 +499,11 @@ public final class SamlRealm extends Realm implements Releasable {
HttpClientBuilder builder = HttpClientBuilder.create();
// ssl setup
Settings sslSettings = config.settings().getByPrefix(SamlRealmSettings.SSL_PREFIX);
boolean isHostnameVerificationEnabled = sslService.getVerificationMode(sslSettings, Settings.EMPTY).isHostnameVerificationEnabled();
final String sslKey = RealmSettings.getFullSettingKey(config, SamlRealmSettings.SSL_PREFIX);
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(sslKey);
boolean isHostnameVerificationEnabled = sslConfiguration.verificationMode().isHostnameVerificationEnabled();
HostnameVerifier verifier = isHostnameVerificationEnabled ? new DefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslService.sslSocketFactory(sslSettings), verifier);
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslService.sslSocketFactory(sslConfiguration), verifier);
builder.setSSLSocketFactory(factory);
HTTPMetadataResolver resolver = new PrivilegedHTTPMetadataResolver(builder.build(), metadataUrl);

View File

@ -20,7 +20,6 @@ import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportException;
@ -36,6 +35,7 @@ import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.SecurityContext;
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
@ -51,17 +51,15 @@ import static org.elasticsearch.xpack.core.security.SecurityField.setting;
public class SecurityServerTransportInterceptor extends AbstractComponent implements TransportInterceptor {
private static final Function<String, Setting<String>> TRANSPORT_TYPE_SETTING_TEMPLATE = (key) -> new Setting<>(key,
"node", v
-> {
if (v.equals("node") || v.equals("client")) {
return v;
}
throw new IllegalArgumentException("type must be one of [client, node]");
private static final Function<String, Setting<String>> TRANSPORT_TYPE_SETTING_TEMPLATE = key -> new Setting<>(key, "node", v -> {
if (v.equals("node") || v.equals("client")) {
return v;
}
throw new IllegalArgumentException("type must be one of [client, node]");
}, Setting.Property.NodeScope);
private static final String TRANSPORT_TYPE_SETTING_KEY = "xpack.security.type";
public static final Setting<String> TRANSPORT_TYPE_PROFILE_SETTING = Setting.affixKeySetting("transport.profiles.",
public static final Setting.AffixSetting<String> TRANSPORT_TYPE_PROFILE_SETTING = Setting.affixKeySetting("transport.profiles.",
TRANSPORT_TYPE_SETTING_KEY, TRANSPORT_TYPE_SETTING_TEMPLATE);
private final AuthenticationService authcService;
@ -175,17 +173,17 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
}
protected Map<String, ServerTransportFilter> initializeProfileFilters(DestructiveOperations destructiveOperations) {
Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true);
Map<String, ServerTransportFilter> profileFilters = new HashMap<>(profileSettingsMap.size() + 1);
final SSLConfiguration transportSslConfiguration = sslService.getSSLConfiguration(setting("transport.ssl"));
final Map<String, SSLConfiguration> profileConfigurations = SecurityNetty4Transport.getTransportProfileConfigurations(settings,
sslService, transportSslConfiguration);
Map<String, ServerTransportFilter> profileFilters = new HashMap<>(profileConfigurations.size() + 1);
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
final boolean transportSSLEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
Settings profileSettings = entry.getValue();
final Settings profileSslSettings = SecurityNetty4Transport.profileSslSettings(profileSettings);
final boolean extractClientCert = transportSSLEnabled &&
sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings);
String type = TRANSPORT_TYPE_SETTING_TEMPLATE.apply(TRANSPORT_TYPE_SETTING_KEY).get(entry.getValue());
for (Map.Entry<String, SSLConfiguration> entry : profileConfigurations.entrySet()) {
final SSLConfiguration profileConfiguration = entry.getValue();
final boolean extractClientCert = transportSSLEnabled && sslService.isSSLClientAuthEnabled(profileConfiguration);
final String type = TRANSPORT_TYPE_PROFILE_SETTING.getConcreteSettingForNamespace(entry.getKey()).get(settings);
switch (type) {
case "client":
profileFilters.put(entry.getKey(), new ServerTransportFilter.ClientProfile(authcService, authzService,
@ -202,12 +200,6 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
}
}
if (!profileFilters.containsKey(TcpTransport.DEFAULT_PROFILE)) {
final boolean extractClientCert = transportSSLEnabled && sslService.isSSLClientAuthEnabled(transportSSLSettings);
profileFilters.put(TcpTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
threadPool.getThreadContext(), extractClientCert, destructiveOperations, reservedRealmEnabled, securityContext));
}
return Collections.unmodifiableMap(profileFilters);
}

View File

@ -32,7 +32,6 @@ import static org.elasticsearch.xpack.core.security.transport.SSLExceptionHelper
public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport {
private final IPFilter ipFilter;
private final Settings sslSettings;
private final SSLService sslService;
private final SSLConfiguration sslConfiguration;
@ -42,10 +41,9 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
super(settings, networkService, bigArrays, threadPool, xContentRegistry, dispatcher);
this.ipFilter = ipFilter;
final boolean ssl = HTTP_SSL_ENABLED.get(settings);
this.sslSettings = SSLService.getHttpTransportSSLSettings(settings);
this.sslService = sslService;
if (ssl) {
this.sslConfiguration = sslService.sslConfiguration(sslSettings, Settings.EMPTY);
this.sslConfiguration = sslService.getHttpTransportSSLConfiguration();
if (sslService.isConfigurationValidForServerUsage(sslConfiguration) == false) {
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " +
"[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting");

View File

@ -42,7 +42,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
@ -74,22 +73,12 @@ public class SecurityNioTransport extends NioTransport {
this.authenticator = authenticator;
this.sslService = sslService;
this.sslEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
if (sslEnabled) {
Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true);
Map<String, SSLConfiguration> profileConfiguration = new HashMap<>(profileSettingsMap.size() + 1);
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
Settings profileSettings = entry.getValue();
final Settings profileSslSettings = SecurityNetty4Transport.profileSslSettings(profileSettings);
SSLConfiguration configuration = sslService.sslConfiguration(profileSslSettings, transportSSLSettings);
profileConfiguration.put(entry.getKey(), configuration);
}
if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslService.sslConfiguration(transportSSLSettings, Settings.EMPTY));
}
final SSLConfiguration transportConfiguration = sslService.getSSLConfiguration(setting("transport.ssl."));
Map<String, SSLConfiguration> profileConfiguration = SecurityNetty4Transport.getTransportProfileConfigurations(settings,
sslService, transportConfiguration);
this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration);
} else {
profileConfiguration = Collections.emptyMap();
}

View File

@ -83,7 +83,7 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
}
private BootstrapCheck.BootstrapCheckResult runCheck(Settings settings, Environment env) throws Exception {
return new PkiRealmBootstrapCheck(settings, new SSLService(settings, env)).check(new BootstrapContext(settings, null));
return new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null));
}
public void testBootstrapCheckWithDisabledRealm() throws Exception {
@ -112,7 +112,7 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
.build();
Environment env = TestEnvironment.newEnvironment(settings);
final PkiRealmBootstrapCheck check = new PkiRealmBootstrapCheck(settings, new SSLService(settings, env));
final PkiRealmBootstrapCheck check = new PkiRealmBootstrapCheck(new SSLService(settings, env));
secureSettings.close();
assertThat(check.check(new BootstrapContext(settings, null)).isFailure(), Matchers.equalTo(expectFail));
}

View File

@ -20,6 +20,7 @@ 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;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
@ -140,9 +141,25 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
return false;
}
/**
* Creates a realm with the provided settings, rebuilds the SSL Service to be aware of the new realm, and then returns
* the RealmConfig
*/
private RealmConfig setupRealm(String realmName, Settings settings) {
final Settings merged = Settings.builder()
.put(settings)
.normalizePrefix("xpack.security.authc.realms." + realmName + ".")
.put(globalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(merged);
this.sslService = new SSLService(merged, env);
return new RealmConfig(realmName, settings, merged, env, new ThreadContext(merged));
}
public void testAuthenticateUserPrincipleName() throws Exception {
Settings settings = settings();
RealmConfig config = new RealmConfig("testAuthenticateUserPrincipleName", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testAuthenticateUserPrincipleName", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -158,7 +175,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
public void testAuthenticateSAMAccountName() throws Exception {
Settings settings = settings();
RealmConfig config = new RealmConfig("testAuthenticateSAMAccountName", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testAuthenticateSAMAccountName", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -182,7 +199,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
public void testAuthenticateCachesSuccessfulAuthentications() throws Exception {
Settings settings = settings();
RealmConfig config = new RealmConfig("testAuthenticateCachesSuccesfulAuthentications", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testAuthenticateCachesSuccesfulAuthentications", settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -200,7 +217,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
public void testAuthenticateCachingCanBeDisabled() throws Exception {
Settings settings = settings(Settings.builder().put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), -1).build());
RealmConfig config = new RealmConfig("testAuthenticateCachingCanBeDisabled", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testAuthenticateCachingCanBeDisabled", settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -218,7 +235,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
public void testAuthenticateCachingClearsCacheOnRoleMapperRefresh() throws Exception {
Settings settings = settings();
RealmConfig config = new RealmConfig("testAuthenticateCachingClearsCacheOnRoleMapperRefresh", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testAuthenticateCachingClearsCacheOnRoleMapperRefresh", settings);
ActiveDirectorySessionFactory sessionFactory = spy(new ActiveDirectorySessionFactory(config, sslService, threadPool));
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -266,8 +283,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
builder.setSecureSettings(secureSettings);
}
Settings settings = settings(builder.build());
RealmConfig config = new RealmConfig("testUnauthenticatedLookupWithConnectionPool", settings, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testUnauthenticatedLookupWithConnectionPool", settings);
try (ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool)) {
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -284,7 +300,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
Settings settings = settings(Settings.builder()
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
.build());
RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testRealmMapsGroupsToRoles", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -300,7 +316,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
Settings settings = settings(Settings.builder()
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
.build());
RealmConfig config = new RealmConfig("testRealmMapsGroupsToRoles", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testRealmMapsGroupsToRoles", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -318,8 +334,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
.put(ROLE_MAPPING_FILE_SETTING, getDataPath("role_mapping.yml"))
.put("load_balance.type", loadBalanceType)
.build());
RealmConfig config = new RealmConfig("testRealmUsageStats", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testRealmUsageStats", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = new DnRoleMapper(config, resourceWatcherService);
LdapRealm realm = new LdapRealm(LdapRealmSettings.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
@ -337,8 +352,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
public void testDefaultSearchFilters() throws Exception {
Settings settings = settings();
RealmConfig config = new RealmConfig("testDefaultSearchFilters", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testDefaultSearchFilters", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertEquals("(&(objectClass=user)(|(sAMAccountName={0})(userPrincipalName={0}@ad.test.elasticsearch.com)))",
sessionFactory.defaultADAuthenticator.getUserSearchFilter());
@ -352,8 +366,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
.put(ActiveDirectorySessionFactorySettings.AD_UPN_USER_SEARCH_FILTER_SETTING, "(objectClass=upn)")
.put(ActiveDirectorySessionFactorySettings.AD_DOWN_LEVEL_USER_SEARCH_FILTER_SETTING, "(objectClass=down level)")
.build());
RealmConfig config = new RealmConfig("testDefaultSearchFilters", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testDefaultSearchFilters", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertEquals("(objectClass=default)", sessionFactory.defaultADAuthenticator.getUserSearchFilter());
assertEquals("(objectClass=upn)", sessionFactory.upnADAuthenticator.getUserSearchFilter());
@ -364,8 +377,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
Settings settings = Settings.builder()
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.build();
RealmConfig config = new RealmConfig("testBuildUrlFromDomainNameAndDefaultPort", settings, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndDefaultPort", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad.test.elasticsearch.com", 389);
}
@ -375,8 +387,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(ActiveDirectorySessionFactorySettings.AD_LDAP_PORT_SETTING.getKey(), 10389)
.build();
RealmConfig config = new RealmConfig("testBuildUrlFromDomainNameAndCustomPort", settings, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndCustomPort", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad.test.elasticsearch.com", 10389);
}
@ -386,8 +397,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
.put(ActiveDirectorySessionFactorySettings.AD_DOMAIN_NAME_SETTING, "ad.test.elasticsearch.com")
.put(SessionFactorySettings.URLS_SETTING, "ldap://ad01.testing.elastic.co:20389/")
.build();
RealmConfig config = new RealmConfig("testBuildUrlFromDomainNameAndCustomPort", settings, globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = setupRealm("testBuildUrlFromDomainNameAndCustomPort", settings);
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
assertSingleLdapServer(sessionFactory, "ad01.testing.elastic.co", 20389);
}

View File

@ -12,6 +12,7 @@ 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;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
@ -19,6 +20,7 @@ import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.Realm;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.LdapSessionFactorySettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
@ -64,15 +66,15 @@ public class LdapRealmTests extends LdapTestCase {
private ThreadPool threadPool;
private ResourceWatcherService resourceWatcherService;
private Settings globalSettings;
private Settings defaultGlobalSettings;
private SSLService sslService;
@Before
public void init() throws Exception {
threadPool = new TestThreadPool("ldap realm tests");
resourceWatcherService = new ResourceWatcherService(Settings.EMPTY, threadPool);
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
sslService = new SSLService(globalSettings, TestEnvironment.newEnvironment(globalSettings));
defaultGlobalSettings = Settings.builder().put("path.home", createTempDir()).build();
sslService = new SSLService(defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings));
}
@After
@ -85,7 +87,7 @@ public class LdapRealmTests extends LdapTestCase {
String groupSearchBase = "o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
threadPool);
@ -109,7 +111,7 @@ public class LdapRealmTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap =
@ -134,7 +136,7 @@ public class LdapRealmTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
ldapFactory = spy(ldapFactory);
@ -159,7 +161,7 @@ public class LdapRealmTests extends LdapTestCase {
Settings settings = Settings.builder()
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
DnRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
@ -192,7 +194,7 @@ public class LdapRealmTests extends LdapTestCase {
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.put(CachingUsernamePasswordRealmSettings.CACHE_TTL_SETTING.getKey(), -1)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
ldapFactory = spy(ldapFactory);
@ -219,8 +221,18 @@ public class LdapRealmTests extends LdapTestCase {
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, threadPool, LdapRealmSettings.LDAP_TYPE);
final String realmName = "test-ldap-realm";
final Settings globalSettings = Settings.builder()
.put(settings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, settings, globalSettings, env, new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(globalSettings, env), threadPool,
LdapRealmSettings.LDAP_TYPE);
assertThat(sessionFactory, is(instanceOf(LdapSessionFactory.class)));
}
@ -235,8 +247,16 @@ public class LdapRealmTests extends LdapTestCase {
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, sslService, threadPool, LdapRealmSettings.LDAP_TYPE);
final String realmName = "test-ldap-realm-user-search";
final Settings globalSettings = Settings.builder()
.put(settings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, settings, globalSettings, env, new ThreadContext(globalSettings));
SessionFactory sessionFactory = LdapRealm.sessionFactory(config, new SSLService(globalSettings, env), threadPool,
LdapRealmSettings.LDAP_TYPE);
try {
assertThat(sessionFactory, is(instanceOf(LdapUserSearchSessionFactory.class)));
} finally {
@ -259,7 +279,7 @@ public class LdapRealmTests extends LdapTestCase {
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealmSettings.LDAP_TYPE));
assertThat(e.getMessage(),
@ -275,7 +295,7 @@ public class LdapRealmTests extends LdapTestCase {
.put("group_search.scope", LdapSearchScope.SUB_TREE)
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm-user-search", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LdapRealm.sessionFactory(config, null, threadPool, LdapRealmSettings.LDAP_TYPE));
assertThat(e.getMessage(),
@ -292,7 +312,7 @@ public class LdapRealmTests extends LdapTestCase {
.put(DnRoleMapperSettings.ROLE_MAPPING_FILE_SETTING.getKey(),
getDataPath("/org/elasticsearch/xpack/security/authc/support/role_mapping.yml"))
.build();
RealmConfig config = new RealmConfig("test-ldap-realm-userdn", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm-userdn", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory,
@ -319,7 +339,7 @@ public class LdapRealmTests extends LdapTestCase {
String groupSearchBase = "o=sevenSeas";
String userTemplate = VALID_USER_TEMPLATE;
Settings settings = buildLdapSettings(new String[] { url.toString() }, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
RealmConfig config = new RealmConfig("test-ldap-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = new RealmConfig("test-ldap-realm", settings, defaultGlobalSettings, TestEnvironment.newEnvironment(defaultGlobalSettings), new ThreadContext(defaultGlobalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapRealm ldap = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService),
threadPool);
@ -353,9 +373,17 @@ public class LdapRealmTests extends LdapTestCase {
settings.put("user_search.base_dn", "");
}
RealmConfig config = new RealmConfig("ldap-realm", settings.build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
final Settings realmSettings = settings.build();
final String realmName = "ldap-realm";
final Settings globalSettings = Settings.builder()
.put(realmSettings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put(defaultGlobalSettings)
.build();
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final RealmConfig config = new RealmConfig(realmName, realmSettings, globalSettings, env, new ThreadContext(globalSettings));
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, sslService, threadPool);
LdapSessionFactory ldapFactory = new LdapSessionFactory(config, new SSLService(globalSettings, env), threadPool);
LdapRealm realm = new LdapRealm(LdapRealmSettings.LDAP_TYPE, config, ldapFactory,
new DnRoleMapper(config, resourceWatcherService), threadPool);
@ -363,7 +391,7 @@ public class LdapRealmTests extends LdapTestCase {
realm.usageStats(future);
Map<String, Object> stats = future.get();
assertThat(stats, is(notNullValue()));
assertThat(stats, hasEntry("name", "ldap-realm"));
assertThat(stats, hasEntry("name", realmName));
assertThat(stats, hasEntry("order", realm.order()));
assertThat(stats, hasEntry("size", 0));
assertThat(stats, hasEntry("ssl", false));

View File

@ -15,6 +15,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
@ -59,16 +60,13 @@ public class LdapTestUtils {
options.setConnectTimeoutMillis(Math.toIntExact(SessionFactorySettings.TIMEOUT_DEFAULT.millis()));
options.setResponseTimeoutMillis(SessionFactorySettings.TIMEOUT_DEFAULT.millis());
Settings connectionSettings;
final SSLConfiguration sslConfiguration;
if (useGlobalSSL) {
connectionSettings = Settings.EMPTY;
sslConfiguration = sslService.getSSLConfiguration("_global");
} else {
MockSecureSettings connSecureSettings = new MockSecureSettings();
connSecureSettings.setString("truststore.secure_password", "changeit");
connectionSettings = Settings.builder().put("truststore.path", truststore)
.setSecureSettings(connSecureSettings).build();
sslConfiguration = sslService.getSSLConfiguration("xpack.security.authc.realms.foo.ssl");
}
return LdapUtils.privilegedConnect(() -> new LDAPConnection(sslService.sslSocketFactory(connectionSettings), options,
return LdapUtils.privilegedConnect(() -> new LDAPConnection(sslService.sslSocketFactory(sslConfiguration), options,
ldapurl.getHost(), ldapurl.getPort(), bindDN, bindPassword));
}
}

View File

@ -19,12 +19,15 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.core.ssl.VerificationMode;
import org.junit.After;
import org.junit.Before;
import java.util.function.Function;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
@ -65,34 +68,39 @@ public class SessionFactoryTests extends ESTestCase {
.put(SessionFactorySettings.FOLLOW_REFERRALS_SETTING, "false")
.build();
final Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
RealmConfig realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment, new ThreadContext(Settings.EMPTY));
LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment),
logger);
final String realmName = "conn_settings";
final Function<Settings, Settings> globalSettings = realmSettings -> Settings.builder()
.put(realmSettings)
.normalizePrefix(RealmSettings.PREFIX + realmName + ".")
.put("path.home", createTempDir())
.build();
final Environment environment = TestEnvironment.newEnvironment(globalSettings.apply(settings));
final Function<Settings, SSLService> sslService = realmSettings -> new SSLService(globalSettings.apply(realmSettings), environment);
final ThreadContext threadContext = new ThreadContext(environment.settings());
RealmConfig realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext);
LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger);
assertThat(options.followReferrals(), is(equalTo(false)));
assertThat(options.allowConcurrentSocketFactoryUse(), is(equalTo(true)));
assertThat(options.getConnectTimeoutMillis(), is(equalTo(10)));
assertThat(options.getResponseTimeoutMillis(), is(equalTo(20L)));
assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class)));
assertWarnings("the setting [xpack.security.authc.realms.conn settings.hostname_verification] has been deprecated and will be " +
"removed in a future version. use [xpack.security.authc.realms.conn settings.ssl.verification_mode] instead");
assertWarnings("the setting [xpack.security.authc.realms." + realmName + ".hostname_verification] has been deprecated" +
" and will be removed in a future version. use [xpack.security.authc.realms." + realmName + ".ssl.verification_mode] instead");
settings = Settings.builder().put("ssl.verification_mode", VerificationMode.CERTIFICATE).build();
realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment, new ThreadContext(Settings.EMPTY));
options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment),
logger);
realmConfig = new RealmConfig(realmName, settings, globalSettings.apply(settings), environment, threadContext);
options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger);
assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class)));
settings = Settings.builder().put("ssl.verification_mode", VerificationMode.NONE).build();
realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment, new ThreadContext(Settings.EMPTY));
options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment),
logger);
realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext);
options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger);
assertThat(options.getSSLSocketVerifier(), is(instanceOf(TrustAllSSLSocketVerifier.class)));
settings = Settings.builder().put("ssl.verification_mode", VerificationMode.FULL).build();
realmConfig = new RealmConfig("conn settings", settings, environment.settings(), environment, new ThreadContext(Settings.EMPTY));
options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment),
logger);
realmConfig = new RealmConfig(realmName, settings, environment.settings(), environment, threadContext);
options = SessionFactory.connectionOptions(realmConfig, sslService.apply(settings), logger);
assertThat(options.getSSLSocketVerifier(), is(instanceOf(HostNameSSLSocketVerifier.class)));
}

View File

@ -20,6 +20,7 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
import org.elasticsearch.xpack.core.ssl.SSLClientAuth;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.junit.Before;
@ -200,7 +201,9 @@ public class SecurityNetty4ServerTransportTests extends ESTestCase {
assertFalse(engine.getWantClientAuth());
// get the global and verify that it is different in that it requires client auth
final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
SSLConfiguration configuration = sslService.getSSLConfiguration("xpack.ssl");
assertNotNull(configuration);
final SSLEngine globalEngine = sslService.createSSLEngine(configuration, null, -1);
assertTrue(globalEngine.getNeedClientAuth());
assertFalse(globalEngine.getWantClientAuth());
}

View File

@ -32,12 +32,12 @@ import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import javax.net.SocketFactory;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
@ -160,7 +160,8 @@ public class SimpleSecurityNioTransportTests extends AbstractSimpleTransportTest
@SuppressForbidden(reason = "Need to open socket connection")
public void testRenegotiation() throws Exception {
SSLService sslService = createSSLService();
SocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY);
final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration("xpack.ssl");
SocketFactory factory = sslService.sslSocketFactory(sslConfiguration);
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
SocketAccess.doPrivileged(() -> socket.connect(serviceA.boundAddress().publishAddress().address()));

View File

@ -28,6 +28,7 @@ import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.core.TestXPackTransportClient;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.security.LocalStateSecurity;
@ -121,8 +122,9 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nodeClientUsername(),
new String(nodeClientPassword().getChars())));
SSLConfiguration sslConfiguration = service.getSSLConfiguration("xpack.ssl");
try (CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(service.sslSocketFactory(Settings.EMPTY),
.setSSLSocketFactory(new SSLConnectionSocketFactory(service.sslSocketFactory(sslConfiguration),
SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
.setDefaultCredentialsProvider(provider).build();
CloseableHttpResponse response = SocketAccess.doPrivileged(() -> client.execute(new HttpGet(getNodeUrl())))) {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import javax.net.ssl.SSLHandshakeException;
@ -95,7 +96,8 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
.build();
String node = randomFrom(internalCluster().getNodeNames());
SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings));
SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(settings);
SSLConfiguration sslConfiguration = sslService.getSSLConfiguration("xpack.ssl");
SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(sslConfiguration);
TransportAddress address = internalCluster()
.getInstance(Transport.class, node).boundAddress().publishAddress();
try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) {

View File

@ -19,6 +19,7 @@ import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.PemUtils;
import org.elasticsearch.xpack.core.ssl.RestrictedTrustManager;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -212,7 +213,8 @@ public class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
String node = randomFrom(internalCluster().getNodeNames());
SSLService sslService = new SSLService(settings, TestEnvironment.newEnvironment(settings));
SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(settings);
SSLConfiguration sslConfiguration = sslService.getSSLConfiguration("xpack.ssl");
SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(sslConfiguration);
TransportAddress address = internalCluster().getInstance(Transport.class, node).boundAddress().publishAddress();
try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) {
assertThat(socket.isConnected(), is(true));

View File

@ -40,6 +40,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.internal.io.Streams;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
import org.elasticsearch.xpack.core.ssl.SSLService;
import org.elasticsearch.xpack.watcher.common.http.auth.ApplicableHttpAuth;
import org.elasticsearch.xpack.watcher.common.http.auth.HttpAuthRegistry;
@ -83,10 +84,10 @@ public class HttpClient extends AbstractComponent implements Closeable {
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
// ssl setup
Settings sslSettings = settings.getByPrefix(SETTINGS_SSL_PREFIX);
boolean isHostnameVerificationEnabled = sslService.getVerificationMode(sslSettings, Settings.EMPTY).isHostnameVerificationEnabled();
SSLConfiguration sslConfiguration = sslService.getSSLConfiguration(SETTINGS_SSL_PREFIX);
boolean isHostnameVerificationEnabled = sslConfiguration.verificationMode().isHostnameVerificationEnabled();
HostnameVerifier verifier = isHostnameVerificationEnabled ? new DefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslService.sslSocketFactory(sslSettings), verifier);
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslService.sslSocketFactory(sslConfiguration), verifier);
clientBuilder.setSSLSocketFactory(factory);
clientBuilder.evictExpiredConnections();

View File

@ -55,6 +55,7 @@ public class OpenLdapTests extends ESTestCase {
private static final String HAWKEYE_DN = "uid=hawkeye,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
public static final String LDAPTRUST_PATH = "/idptrust.jks";
private static final SecureString PASSWORD_SECURE_STRING = new SecureString(PASSWORD.toCharArray());
public static final String REALM_NAME = "oldap-test";
private boolean useGlobalSSL;
private SSLService sslService;
@ -91,18 +92,18 @@ public class OpenLdapTests extends ESTestCase {
builder.put("xpack.ssl.truststore.path", truststore);
mockSecureSettings.setString("xpack.ssl.truststore.secure_password", "changeit");
// fake realm to load config with certificate verification mode
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
mockSecureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit");
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
// configure realm to load config with certificate verification mode
builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.path", truststore);
mockSecureSettings.setString("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.secure_password", "changeit");
builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE);
} else {
// fake realms so ssl will get loaded
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore);
mockSecureSettings.setString("xpack.security.authc.realms.foo.ssl.truststore.secure_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);
mockSecureSettings.setString("xpack.security.authc.realms.bar.ssl.truststore.secure_password", "changeit");
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.path", truststore);
mockSecureSettings.setString("xpack.security.authc.realms." + REALM_NAME + ".ssl.truststore.secure_password", "changeit");
builder.put("xpack.security.authc.realms." + REALM_NAME + ".ssl.verification_mode", VerificationMode.CERTIFICATE);
}
globalSettings = builder.setSecureSettings(mockSecureSettings).build();
Environment environment = TestEnvironment.newEnvironment(globalSettings);
@ -114,8 +115,8 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase,
LdapSearchScope.ONE_LEVEL), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
LdapSearchScope.ONE_LEVEL), globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" };
@ -132,8 +133,8 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "cn=Avengers,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase,
LdapSearchScope.BASE), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
RealmConfig config = new RealmConfig(REALM_NAME, buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase,
LdapSearchScope.BASE), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" };
@ -148,12 +149,12 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
Settings settings = Settings.builder()
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("group_search.filter", "(&(objectclass=posixGroup)(memberUid={0}))")
.put("group_search.user_attribute", "uid")
.build();
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("group_search.filter", "(&(objectclass=posixGroup)(memberUid={0}))")
.put("group_search.user_attribute", "uid")
.build();
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
try (LdapSession ldap = session(sessionFactory, "selvig", PASSWORD_SECURE_STRING)) {
@ -166,17 +167,17 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
Settings settings = Settings.builder()
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("group_search.filter", "(objectClass=*)")
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond
.build();
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
.put("group_search.filter", "(objectClass=*)")
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond
.build();
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
LDAPException expected = expectThrows(LDAPException.class,
() -> session(sessionFactory, "thor", PASSWORD_SECURE_STRING).groups(new PlainActionFuture<>()));
() -> session(sessionFactory, "thor", PASSWORD_SECURE_STRING).groups(new PlainActionFuture<>()));
assertThat(expected.getMessage(), containsString("A client-side timeout was encountered while waiting"));
}
@ -185,22 +186,22 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
Settings settings = Settings.builder()
// The certificate used in the vagrant box is valid for "localhost", but not for "127.0.0.1"
.put(buildLdapSettings(OPEN_LDAP_IP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("ssl.verification_mode", VerificationMode.FULL)
.build();
// The certificate used in the vagrant box is valid for "localhost", but not for "127.0.0.1"
.put(buildLdapSettings(OPEN_LDAP_IP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("ssl.verification_mode", VerificationMode.FULL)
.build();
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String user = "blackwidow";
UncategorizedExecutionException e = expectThrows(UncategorizedExecutionException.class,
() -> session(sessionFactory, user, PASSWORD_SECURE_STRING));
() -> session(sessionFactory, user, PASSWORD_SECURE_STRING));
assertThat(e.getCause(), instanceOf(ExecutionException.class));
assertThat(e.getCause().getCause(), instanceOf(LDAPException.class));
assertThat(e.getCause().getCause().getMessage(),
anyOf(containsString("Hostname verification failed"), containsString("peer not authenticated")));
anyOf(containsString("Hostname verification failed"), containsString("peer not authenticated")));
}
public void testStandardLdapConnectionHostnameVerificationSuccess() throws Exception {
@ -208,13 +209,13 @@ public class OpenLdapTests extends ESTestCase {
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
Settings settings = Settings.builder()
// The certificate used in the vagrant box is valid for "localhost" (but not for "127.0.0.1")
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("ssl.verification_mode", VerificationMode.FULL)
.build();
// The certificate used in the vagrant box is valid for "localhost" (but not for "127.0.0.1")
.put(buildLdapSettings(OPEN_LDAP_DNS_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
.put("ssl.verification_mode", VerificationMode.FULL)
.build();
RealmConfig config = new RealmConfig("oldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(Settings.EMPTY));
new ThreadContext(Settings.EMPTY));
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
final String user = "blackwidow";
@ -260,9 +261,9 @@ public class OpenLdapTests extends ESTestCase {
return builder.build();
}
return builder
.put("ssl.truststore.path", getDataPath(LDAPTRUST_PATH))
.put("ssl.truststore.password", "changeit")
.build();
.put("ssl.truststore.path", getDataPath(LDAPTRUST_PATH))
.put("ssl.truststore.password", "changeit")
.build();
}
private LdapSession session(SessionFactory factory, String username, SecureString password) {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.OpenLdapTests;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@ -39,6 +40,7 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
@TestLogging("org.elasticsearch.xpack.core.ssl.SSLService:TRACE")
public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
private Settings globalSettings;
@ -77,7 +79,8 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
.put("user_search.base_dn", userSearchBase)
.put("group_search.user_attribute", "uid")
.put("bind_dn", "uid=blackwidow,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com")
.put("user_search.pool.enabled", randomBoolean());
.put("user_search.pool.enabled", randomBoolean())
.put("ssl.verification_mode", "full");
if (useSecureBindPassword) {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("secure_bind_password", OpenLdapTests.PASSWORD);
@ -89,11 +92,11 @@ public class OpenLdapUserSearchSessionFactoryTests extends ESTestCase {
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
Settings.Builder builder = Settings.builder()
.put(globalSettings, false);
builder.put(Settings.builder().put(config.settings(), false).normalizePrefix("xpack.security.authc.realms.ldap.").build());
builder.put(Settings.builder().put(config.settings(), false).normalizePrefix("xpack.security.authc.realms.oldap-test.").build());
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.merge(globalSecureSettings);
if (useSecureBindPassword) {
secureSettings.setString("xpack.security.authc.realms.ldap.secure_bind_password", OpenLdapTests.PASSWORD);
secureSettings.setString("xpack.security.authc.realms.oldap-test.secure_bind_password", OpenLdapTests.PASSWORD);
}
builder.setSecureSettings(secureSettings);
Settings settings = builder.build();