Migrate xpack to use the common ssl configuration
This change migrates xpack (security, watcher, and monitoring) to use the common ssl configuration for the elastic stack. As part of this work, several aspects of how we deal with SSL has been modified. From a functionality perspective, an xpack wide configuration for SSL was added and all of the code that needs SSL uses the SSLService now. The following is a list of all of the aspects of xpack that can have their own SSL configuration, which are separate from the xpack wide configuration: * Transport * Transport profiles * HTTP Transport * Realms * Monitoring Exporters * HTTP Client In terms of the code, some cleanups were made with these changes. SSLConfiguration is now a concrete class and SSLConfiguration.Custom and SSLConfiguration.Global have been removed. The validate method on key and trust configurations has been removed and these classes will now throw exceptions when they are constructed with bad values. The OptionalSettings helper class has been removed as it was just a file with one line functions that made the code harder to understand. The SSL configuration and service classes have been moved from the security source directories to the main xpack source set. The SSLService now handles more of the configuration of the SSLEngine it returns to prevent callers from having to handle those aspects. The settings that get registered for SSL have been moved to XPackSettings. Also included in this PR is a update to the docs around SSL. This includes a large simplification to the documentation in that the certificate authority configuration section has been removed and the process that is documented for generating certificates only includes the CLI tool that we bundle. Closes elastic/elasticsearch#3104 Closes elastic/elasticsearch#2971 Closes elastic/elasticsearch#3164 Original commit: elastic/x-pack-elasticsearch@5bd9e5ef38
This commit is contained in:
parent
54103127d0
commit
ad9a7c9b96
|
@ -172,8 +172,8 @@ integTest {
|
|||
|
||||
setting 'xpack.security.transport.ssl.enabled', 'true'
|
||||
setting 'xpack.security.http.ssl.enabled', 'true'
|
||||
setting 'xpack.security.ssl.keystore.path', nodeKeystore.name
|
||||
setting 'xpack.security.ssl.keystore.password', 'keypass'
|
||||
setting 'xpack.ssl.keystore.path', nodeKeystore.name
|
||||
setting 'xpack.ssl.keystore.password', 'keypass'
|
||||
|
||||
plugin ':x-plugins:elasticsearch:x-pack'
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.junit.After;
|
||||
|
@ -71,9 +70,9 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
|||
final Settings.Builder builder =
|
||||
Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.keystore.path", clientKeyStore)
|
||||
.put("xpack.security.ssl.keystore.password", KEYSTORE_PASS);
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.keystore.path", clientKeyStore)
|
||||
.put("xpack.ssl.keystore.password", KEYSTORE_PASS);
|
||||
if (useSecurity3) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3);
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.elasticsearch.xpack.monitoring.rest.action.RestMonitoringBulkAction;
|
|||
import org.elasticsearch.plugins.ActionPlugin;
|
||||
import org.elasticsearch.rest.RestHandler;
|
||||
import org.elasticsearch.xpack.security.InternalClient;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -98,7 +99,7 @@ public class Monitoring implements ActionPlugin {
|
|||
}
|
||||
|
||||
public Collection<Object> createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService,
|
||||
LicenseService licenseService) {
|
||||
LicenseService licenseService, SSLService sslService) {
|
||||
if (enabled == false || tribeNode) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -107,8 +108,10 @@ public class Monitoring implements ActionPlugin {
|
|||
final MonitoringSettings monitoringSettings = new MonitoringSettings(settings, clusterSettings);
|
||||
final CleanerService cleanerService = new CleanerService(settings, clusterSettings, threadPool, licenseState);
|
||||
|
||||
// TODO do exporters and their ssl config really need to be dynamic? https://github.com/elastic/x-plugins/issues/3117
|
||||
final SSLService dynamicSSLService = sslService.createDynamicSSLService();
|
||||
Map<String, Exporter.Factory> exporterFactories = new HashMap<>();
|
||||
exporterFactories.put(HttpExporter.TYPE, config -> new HttpExporter(config, env));
|
||||
exporterFactories.put(HttpExporter.TYPE, config -> new HttpExporter(config, env, dynamicSSLService));
|
||||
exporterFactories.put(LocalExporter.TYPE, config -> new LocalExporter(config, client, clusterService, cleanerService));
|
||||
final Exporters exporters = new Exporters(settings, exporterFactories, clusterService);
|
||||
|
||||
|
|
|
@ -32,14 +32,12 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
|
|||
import org.elasticsearch.xpack.monitoring.agent.resolver.MonitoringIndexNameResolver;
|
||||
import org.elasticsearch.xpack.monitoring.agent.resolver.ResolversRegistry;
|
||||
import org.elasticsearch.xpack.monitoring.support.VersionUtils;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -50,10 +48,7 @@ import java.net.MalformedURLException;
|
|||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
|
@ -106,13 +101,6 @@ public class HttpExporter extends Exporter {
|
|||
*/
|
||||
public static final String PIPELINE_CHECK_TIMEOUT_SETTING = "index.pipeline.master_timeout";
|
||||
|
||||
public static final String SSL_SETTING = "ssl";
|
||||
public static final String SSL_PROTOCOL_SETTING = "protocol";
|
||||
public static final String SSL_TRUSTSTORE_SETTING = "truststore.path";
|
||||
public static final String SSL_TRUSTSTORE_PASSWORD_SETTING = "truststore.password";
|
||||
public static final String SSL_TRUSTSTORE_ALGORITHM_SETTING = "truststore.algorithm";
|
||||
public static final String SSL_HOSTNAME_VERIFICATION_SETTING = SSL_SETTING + ".hostname_verification";
|
||||
|
||||
/**
|
||||
* Minimum supported version of the remote monitoring cluster.
|
||||
* <p>
|
||||
|
@ -156,7 +144,7 @@ public class HttpExporter extends Exporter {
|
|||
final ConnectionKeepAliveWorker keepAliveWorker;
|
||||
Thread keepAliveThread;
|
||||
|
||||
public HttpExporter(Config config, Environment env) {
|
||||
public HttpExporter(Config config, Environment env, SSLService sslService) {
|
||||
super(config);
|
||||
|
||||
this.env = env;
|
||||
|
@ -174,8 +162,9 @@ public class HttpExporter extends Exporter {
|
|||
keepAlive = config.settings().getAsBoolean(CONNECTION_KEEP_ALIVE_SETTING, true);
|
||||
keepAliveWorker = new ConnectionKeepAliveWorker();
|
||||
|
||||
sslSocketFactory = createSSLSocketFactory(config.settings().getAsSettings(SSL_SETTING));
|
||||
hostnameVerification = config.settings().getAsBoolean(SSL_HOSTNAME_VERIFICATION_SETTING, true);
|
||||
final Settings sslSettings = config.settings().getByPrefix("ssl.");
|
||||
sslSocketFactory = sslService.sslSocketFactory(sslSettings);
|
||||
hostnameVerification = sslService.getVerificationMode(sslSettings, Settings.EMPTY).isHostnameVerificationEnabled();
|
||||
|
||||
resolvers = new ResolversRegistry(config.settings());
|
||||
// Checks that required templates are loaded
|
||||
|
@ -760,64 +749,6 @@ public class HttpExporter extends Exporter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL Initialization *
|
||||
*/
|
||||
public SSLSocketFactory createSSLSocketFactory(Settings settings) {
|
||||
if (settings.names().isEmpty()) {
|
||||
logger.trace("no ssl context configured");
|
||||
return null;
|
||||
}
|
||||
SSLContext sslContext;
|
||||
// Initialize sslContext
|
||||
try {
|
||||
String protocol = settings.get(SSL_PROTOCOL_SETTING, "TLS");
|
||||
String trustStore = settings.get(SSL_TRUSTSTORE_SETTING, System.getProperty("javax.net.ssl.trustStore"));
|
||||
String trustStorePassword = settings.get(SSL_TRUSTSTORE_PASSWORD_SETTING,
|
||||
System.getProperty("javax.net.ssl.trustStorePassword"));
|
||||
String trustStoreAlgorithm = settings.get(SSL_TRUSTSTORE_ALGORITHM_SETTING,
|
||||
System.getProperty("ssl.TrustManagerFactory.algorithm"));
|
||||
|
||||
if (trustStore == null) {
|
||||
throw new SettingsException("missing required setting [" + SSL_TRUSTSTORE_SETTING + "]");
|
||||
}
|
||||
|
||||
if (trustStoreAlgorithm == null) {
|
||||
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
}
|
||||
|
||||
logger.debug("using ssl trust store [{}] with algorithm [{}]", trustStore, trustStoreAlgorithm);
|
||||
|
||||
Path trustStorePath = env.configFile().resolve(trustStore);
|
||||
if (!Files.exists(trustStorePath)) {
|
||||
throw new SettingsException("could not find trust store file [" + trustStorePath + "]");
|
||||
}
|
||||
|
||||
TrustManager[] trustManagers;
|
||||
try (InputStream trustStoreStream = Files.newInputStream(trustStorePath)) {
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
ks.load(trustStoreStream, trustStorePassword == null ? null : trustStorePassword.toCharArray());
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
|
||||
// Retrieve the trust managers from the factory
|
||||
trustManagers = trustFactory.getTrustManagers();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
|
||||
sslContext = SSLContext.getInstance(protocol);
|
||||
sslContext.init(null, trustManagers, null);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize ssl", e);
|
||||
}
|
||||
return sslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
BasicAuth resolveAuth(Settings setting) {
|
||||
String username = setting.get(AUTH_USERNAME_SETTING, null);
|
||||
String password = setting.get(AUTH_PASSWORD_SETTING, null);
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.SettingsException;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -37,7 +38,7 @@ public class HttpExporterSimpleTests extends ESTestCase {
|
|||
final Exporter.Config config = createConfig("_http", builder.build());
|
||||
|
||||
final SettingsException exception = expectThrows(SettingsException.class, () -> {
|
||||
new HttpExporter(config, environment);
|
||||
new HttpExporter(config, environment, new SSLService(builder.build(), environment));
|
||||
});
|
||||
|
||||
assertThat(exception.getMessage(), equalTo(expected));
|
||||
|
@ -58,7 +59,7 @@ public class HttpExporterSimpleTests extends ESTestCase {
|
|||
final Exporter.Config config = createConfig("_http", builder.build());
|
||||
|
||||
final SettingsException exception = expectThrows(SettingsException.class, () -> {
|
||||
new HttpExporter(config, environment);
|
||||
new HttpExporter(config, environment, new SSLService(builder.build(), environment));
|
||||
});
|
||||
|
||||
assertThat(exception.getMessage(), equalTo(expected));
|
||||
|
@ -80,7 +81,7 @@ public class HttpExporterSimpleTests extends ESTestCase {
|
|||
final Exporter.Config config = createConfig("_http", builder.build());
|
||||
|
||||
final SettingsException exception = expectThrows(SettingsException.class, () -> {
|
||||
new HttpExporter(config, environment);
|
||||
new HttpExporter(config, environment, new SSLService(builder.build(), environment));
|
||||
});
|
||||
|
||||
assertThat(exception.getMessage(), equalTo("missing required setting [xpack.monitoring.exporters._http.host]"));
|
||||
|
@ -106,7 +107,7 @@ public class HttpExporterSimpleTests extends ESTestCase {
|
|||
final Exporter.Config config = createConfig("_http", builder.build());
|
||||
|
||||
final SettingsException exception = expectThrows(SettingsException.class, () -> {
|
||||
new HttpExporter(config, environment);
|
||||
new HttpExporter(config, environment, new SSLService(builder.build(), environment));
|
||||
});
|
||||
|
||||
assertThat(exception.getMessage(), equalTo("[xpack.monitoring.exporters._http.host] invalid host: [" + invalidHost + "]"));
|
||||
|
@ -119,7 +120,7 @@ public class HttpExporterSimpleTests extends ESTestCase {
|
|||
|
||||
final Exporter.Config config = createConfig("_http", builder.build());
|
||||
|
||||
new HttpExporter(config, environment);
|
||||
new HttpExporter(config, environment, new SSLService(builder.build(), environment));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
|
|||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
// TODO: we do not need individual tests for monitoring and security... maybe watcher even has one too?
|
||||
public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase {
|
||||
|
||||
@Override
|
||||
|
@ -40,9 +41,10 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase {
|
|||
.put("xpack.monitoring.exporters._http.enabled", false)
|
||||
.put("xpack.monitoring.exporters._http.auth.username", "_user")
|
||||
.put("xpack.monitoring.exporters._http.auth.password", "_passwd")
|
||||
.put("xpack.monitoring.exporters._http.ssl.truststore.path", "/path/to/truststore")
|
||||
.put("xpack.monitoring.exporters._http.ssl.truststore.password", "_passwd")
|
||||
.put("xpack.monitoring.exporters._http.ssl.hostname_verification", true)
|
||||
.put("xpack.monitoring.exporters._http.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.monitoring.exporters._http.ssl.truststore.password", "truststore-testnode-only")
|
||||
.put("xpack.monitoring.exporters._http.ssl.verification_mode", "full")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -77,7 +79,7 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase {
|
|||
assertNullSetting(settings, "xpack.monitoring.exporters._http.auth.password");
|
||||
assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.truststore.path");
|
||||
assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.truststore.password");
|
||||
assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.hostname_verification");
|
||||
assertNullSetting(settings, "xpack.monitoring.exporters._http.ssl.verification_mode");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ if [ -e "$CONF_DIR" ]; then
|
|||
fi
|
||||
|
||||
cd "$ES_HOME" > /dev/null
|
||||
"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.security.ssl.CertificateTool "${args[@]}"
|
||||
"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.ssl.CertificateTool "${args[@]}"
|
||||
status=$?
|
||||
cd - > /dev/null
|
||||
exit $status
|
||||
|
|
|
@ -5,5 +5,5 @@ rem or more contributor license agreements. Licensed under the Elastic License;
|
|||
rem you may not use this file except in compliance with the Elastic License.
|
||||
|
||||
PUSHD "%~dp0"
|
||||
CALL "%~dp0.in.bat" org.elasticsearch.xpack.security.ssl.CertificateTool %*
|
||||
CALL "%~dp0.in.bat" org.elasticsearch.xpack.ssl.CertificateTool %*
|
||||
POPD
|
||||
|
|
|
@ -96,9 +96,6 @@ import org.elasticsearch.xpack.security.rest.action.user.RestChangePasswordActio
|
|||
import org.elasticsearch.xpack.security.rest.action.user.RestDeleteUserAction;
|
||||
import org.elasticsearch.xpack.security.rest.action.user.RestGetUsersAction;
|
||||
import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfigurationReloader;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.support.OptionalSettings;
|
||||
import org.elasticsearch.xpack.security.transport.SecurityServerTransportService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
|
@ -106,6 +103,7 @@ import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport
|
|||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
|
@ -135,7 +133,8 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
|
||||
public static final String NAME3 = XPackPlugin.SECURITY + "3";
|
||||
public static final String NAME4 = XPackPlugin.SECURITY + "4";
|
||||
public static final Setting<Optional<String>> USER_SETTING = OptionalSettings.createString(setting("user"), Property.NodeScope);
|
||||
public static final Setting<Optional<String>> USER_SETTING =
|
||||
new Setting<>(setting("user"), (String) null, Optional::ofNullable, Property.NodeScope);
|
||||
|
||||
public static final Setting<List<String>> AUDIT_OUTPUTS_SETTING =
|
||||
Setting.listSetting(setting("audit.outputs"),
|
||||
|
@ -149,8 +148,9 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
private final boolean transportClientMode;
|
||||
private final XPackLicenseState licenseState;
|
||||
private final CryptoService cryptoService;
|
||||
private final SSLService sslService;
|
||||
|
||||
public Security(Settings settings, Environment env, XPackLicenseState licenseState) throws IOException {
|
||||
public Security(Settings settings, Environment env, XPackLicenseState licenseState, SSLService sslService) throws IOException {
|
||||
this.settings = settings;
|
||||
this.env = env;
|
||||
this.transportClientMode = XPackPlugin.transportClientMode(settings);
|
||||
|
@ -162,6 +162,7 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
cryptoService = null;
|
||||
}
|
||||
this.licenseState = licenseState;
|
||||
this.sslService = sslService;
|
||||
}
|
||||
|
||||
public CryptoService getCryptoService() {
|
||||
|
@ -180,7 +181,7 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
}
|
||||
modules.add(b -> {
|
||||
// for transport client we still must inject these ssl classes with guice
|
||||
b.bind(SSLService.class).toInstance(new SSLService(settings, null));
|
||||
b.bind(SSLService.class).toInstance(sslService);
|
||||
});
|
||||
|
||||
return modules;
|
||||
|
@ -224,11 +225,6 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
final SecurityContext securityContext = new SecurityContext(settings, threadPool, cryptoService);
|
||||
components.add(securityContext);
|
||||
|
||||
final SSLService sslService = new SSLService(settings, env);
|
||||
// just create the reloader as it will pull all of the loaded ssl configurations and start watching them
|
||||
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService);
|
||||
components.add(sslService);
|
||||
|
||||
// realms construction
|
||||
final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, threadPool);
|
||||
final ReservedRealm reservedRealm = new ReservedRealm(env, settings, nativeUsersStore);
|
||||
|
@ -238,7 +234,7 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
realmFactories.put(ActiveDirectoryRealm.TYPE,
|
||||
config -> new ActiveDirectoryRealm(config, resourceWatcherService, sslService));
|
||||
realmFactories.put(LdapRealm.TYPE, config -> new LdapRealm(config, resourceWatcherService, sslService));
|
||||
realmFactories.put(PkiRealm.TYPE, config -> new PkiRealm(config, resourceWatcherService));
|
||||
realmFactories.put(PkiRealm.TYPE, config -> new PkiRealm(config, resourceWatcherService, sslService));
|
||||
for (XPackExtension extension : extensions) {
|
||||
Map<String, Realm.Factory> newRealms = extension.getRealms();
|
||||
for (Map.Entry<String, Realm.Factory> entry : newRealms.entrySet()) {
|
||||
|
@ -375,12 +371,6 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
// always register for both client and node modes
|
||||
settingsList.add(USER_SETTING);
|
||||
|
||||
// SSL settings
|
||||
SSLService.addSettings(settingsList);
|
||||
|
||||
// transport settings
|
||||
SecurityNetty3Transport.addSettings(settingsList);
|
||||
|
||||
if (transportClientMode) {
|
||||
return settingsList;
|
||||
}
|
||||
|
@ -403,9 +393,6 @@ public class Security implements ActionPlugin, IngestPlugin {
|
|||
AuthenticationService.addSettings(settingsList);
|
||||
AuthorizationService.addSettings(settingsList);
|
||||
|
||||
// HTTP settings
|
||||
SecurityNetty3HttpServerTransport.addSettings(settingsList);
|
||||
|
||||
// encryption settings
|
||||
CryptoService.addSettings(settingsList);
|
||||
|
||||
|
|
|
@ -26,12 +26,13 @@ import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
|||
import org.elasticsearch.xpack.security.authz.store.RolesStore;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
/**
|
||||
*
|
||||
* Indicates whether the features of Security are currently in use
|
||||
*/
|
||||
public class SecurityFeatureSet implements XPackFeatureSet {
|
||||
|
||||
|
@ -114,8 +115,8 @@ public class SecurityFeatureSet implements XPackFeatureSet {
|
|||
|
||||
static Map<String, Object> sslUsage(Settings settings) {
|
||||
Map<String, Object> map = new HashMap<>(2);
|
||||
map.put("http", Collections.singletonMap("enabled", SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings)));
|
||||
map.put("transport", Collections.singletonMap("enabled", SecurityNetty3Transport.SSL_SETTING.get(settings)));
|
||||
map.put("http", Collections.singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
|
||||
map.put("transport", Collections.singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.elasticsearch.xpack.security.authc.RealmConfig;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.AbstractLdapRealm;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -23,7 +23,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
|||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
|
||||
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.elasticsearch.xpack.security.authc.RealmConfig;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.AbstractLdapRealm;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.support.Exceptions;
|
||||
|
||||
import java.util.Locale;
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
|
@ -8,38 +8,39 @@ package org.elasticsearch.xpack.security.authc.pki;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.Realms;
|
||||
import org.elasticsearch.xpack.ssl.CertUtils;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
|
||||
import org.elasticsearch.xpack.security.authc.Realm;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
public class PkiRealm extends Realm {
|
||||
|
||||
public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE";
|
||||
|
@ -49,23 +50,23 @@ public class PkiRealm extends Realm {
|
|||
// For client based cert validation, the auth type must be specified but UNKNOWN is an acceptable value
|
||||
public static final String AUTH_TYPE = "UNKNOWN";
|
||||
|
||||
private final X509TrustManager[] trustManagers;
|
||||
private final X509TrustManager trustManager;
|
||||
private final Pattern principalPattern;
|
||||
private final DnRoleMapper roleMapper;
|
||||
|
||||
|
||||
public PkiRealm(RealmConfig config, ResourceWatcherService watcherService) {
|
||||
this(config, new DnRoleMapper(TYPE, config, watcherService, null));
|
||||
public PkiRealm(RealmConfig config, ResourceWatcherService watcherService, SSLService sslService) {
|
||||
this(config, new DnRoleMapper(TYPE, config, watcherService, null), sslService);
|
||||
}
|
||||
|
||||
// pkg private for testing
|
||||
PkiRealm(RealmConfig config, DnRoleMapper roleMapper) {
|
||||
PkiRealm(RealmConfig config, DnRoleMapper roleMapper, SSLService sslService) {
|
||||
super(TYPE, config);
|
||||
this.trustManagers = trustManagers(config.settings(), config.env());
|
||||
this.trustManager = trustManagers(config);
|
||||
this.principalPattern = Pattern.compile(config.settings().get("username_pattern", DEFAULT_USERNAME_PATTERN),
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
this.roleMapper = roleMapper;
|
||||
checkSSLEnabled(config, logger);
|
||||
checkSSLEnabled(config, sslService);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,7 +82,7 @@ public class PkiRealm extends Realm {
|
|||
@Override
|
||||
public User authenticate(AuthenticationToken authToken) {
|
||||
X509AuthenticationToken token = (X509AuthenticationToken)authToken;
|
||||
if (!isCertificateChainTrusted(trustManagers, token, logger)) {
|
||||
if (isCertificateChainTrusted(trustManager, token, logger) == false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -129,94 +130,95 @@ public class PkiRealm extends Realm {
|
|||
return new X509AuthenticationToken(certificates, principal, dn);
|
||||
}
|
||||
|
||||
static boolean isCertificateChainTrusted(X509TrustManager[] trustManagers, X509AuthenticationToken token, Logger logger) {
|
||||
if (trustManagers.length > 0) {
|
||||
boolean trusted = false;
|
||||
for (X509TrustManager trustManager : trustManagers) {
|
||||
try {
|
||||
trustManager.checkClientTrusted(token.credentials(), AUTH_TYPE);
|
||||
trusted = true;
|
||||
break;
|
||||
} catch (CertificateException e) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"failed certificate validation for principal [{}]", token.principal()), e);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("failed certificate validation for principal [{}]", token.principal());
|
||||
}
|
||||
static boolean isCertificateChainTrusted(X509TrustManager trustManager, X509AuthenticationToken token, Logger logger) {
|
||||
if (trustManager != null) {
|
||||
try {
|
||||
trustManager.checkClientTrusted(token.credentials(), AUTH_TYPE);
|
||||
return true;
|
||||
} catch (CertificateException e) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace((Supplier<?>)
|
||||
() -> new ParameterizedMessage("failed certificate validation for principal [{}]", token.principal()), e);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("failed certificate validation for principal [{}]", token.principal());
|
||||
}
|
||||
}
|
||||
|
||||
return trusted;
|
||||
return false;
|
||||
}
|
||||
|
||||
// No extra trust managers specified, so at this point we can be considered authenticated.
|
||||
return true;
|
||||
}
|
||||
|
||||
static X509TrustManager[] trustManagers(Settings settings, Environment env) {
|
||||
static X509TrustManager trustManagers(RealmConfig realmConfig) {
|
||||
final Settings settings = realmConfig.settings();
|
||||
final Environment env = realmConfig.env();
|
||||
String[] certificateAuthorities = settings.getAsArray("certificate_authorities", null);
|
||||
String truststorePath = settings.get("truststore.path");
|
||||
if (truststorePath == null) {
|
||||
return new X509TrustManager[0];
|
||||
if (truststorePath == null && certificateAuthorities == null) {
|
||||
return null;
|
||||
} else if (truststorePath != null && certificateAuthorities != null) {
|
||||
final String settingPrefix = Realms.REALMS_GROUPS_SETTINGS.getKey() + realmConfig.name() + ".";
|
||||
throw new IllegalArgumentException("[" + settingPrefix + "truststore.path] and [" + settingPrefix + "certificate_authorities]" +
|
||||
" cannot be used at the same time");
|
||||
} else if (truststorePath != null) {
|
||||
return trustManagersFromTruststore(realmConfig);
|
||||
}
|
||||
return trustManagersFromCAs(settings, env);
|
||||
}
|
||||
|
||||
private static X509TrustManager trustManagersFromTruststore(RealmConfig realmConfig) {
|
||||
final Settings settings = realmConfig.settings();
|
||||
String truststorePath = settings.get("truststore.path");
|
||||
String password = settings.get("truststore.password");
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("no truststore password configured");
|
||||
final String settingPrefix = Realms.REALMS_GROUPS_SETTINGS.getKey() + realmConfig.name() + ".";
|
||||
throw new IllegalArgumentException("[" + settingPrefix + "truststore.password] is not configured");
|
||||
}
|
||||
|
||||
String trustStoreAlgorithm = settings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm",
|
||||
TrustManagerFactory.getDefaultAlgorithm()));
|
||||
TrustManager[] trustManagers;
|
||||
try (InputStream in = Files.newInputStream(XPackPlugin.resolveConfigFile(env, truststorePath))) {
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
ks.load(in, password.toCharArray());
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
trustManagers = trustFactory.getTrustManagers();
|
||||
try {
|
||||
return CertUtils.trustManager(truststorePath, password, trustStoreAlgorithm, realmConfig.env());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("failed to load specified truststore", e);
|
||||
}
|
||||
}
|
||||
|
||||
List<X509TrustManager> trustManagerList = new ArrayList<>();
|
||||
for (TrustManager trustManager : trustManagers) {
|
||||
if (trustManager instanceof X509TrustManager) {
|
||||
trustManagerList.add((X509TrustManager) trustManager);
|
||||
}
|
||||
private static X509TrustManager trustManagersFromCAs(Settings settings, Environment env) {
|
||||
String[] certificateAuthorities = settings.getAsArray("certificate_authorities", null);
|
||||
assert certificateAuthorities != null;
|
||||
try {
|
||||
Certificate[] certificates = CertUtils.readCertificates(Arrays.asList(certificateAuthorities), env);
|
||||
return CertUtils.trustManager(certificates);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to load certificate authorities for PKI realm", e);
|
||||
}
|
||||
|
||||
if (trustManagerList.isEmpty()) {
|
||||
throw new IllegalArgumentException("no valid certificates found in truststore");
|
||||
}
|
||||
|
||||
return trustManagerList.toArray(new X509TrustManager[trustManagerList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if both SSL and Client authentication are enabled on at least one network communication layer. If
|
||||
* not an error message will be logged
|
||||
* not an exception will be thrown
|
||||
*
|
||||
* @param config this realm's configuration
|
||||
* @param logger the logger to use if there is a configuration issue
|
||||
* @param sslService the SSLService to use for ssl configurations
|
||||
*/
|
||||
static void checkSSLEnabled(RealmConfig config, Logger logger) {
|
||||
static void checkSSLEnabled(RealmConfig config, SSLService sslService) {
|
||||
Settings settings = config.globalSettings();
|
||||
|
||||
final boolean httpSsl = SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings);
|
||||
final boolean httpClientAuth = SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.get(settings).enabled();
|
||||
// HTTP
|
||||
final boolean httpSsl = HTTP_SSL_ENABLED.get(settings);
|
||||
Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
final boolean httpClientAuth = sslService.isSSLClientAuthEnabled(httpSSLSettings);
|
||||
if (httpSsl && httpClientAuth) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Default Transport
|
||||
final boolean ssl = SecurityNetty3Transport.SSL_SETTING.get(settings);
|
||||
final SSLClientAuth clientAuth = SecurityNetty3Transport.CLIENT_AUTH_SETTING.get(settings);
|
||||
if (ssl && clientAuth.enabled()) {
|
||||
final boolean ssl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
final boolean clientAuthEnabled = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
||||
if (ssl && clientAuthEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -224,13 +226,14 @@ public class PkiRealm extends Realm {
|
|||
Map<String, Settings> groupedSettings = settings.getGroups("transport.profiles.");
|
||||
for (Map.Entry<String, Settings> entry : groupedSettings.entrySet()) {
|
||||
Settings profileSettings = entry.getValue().getByPrefix(Security.settingPrefix());
|
||||
if (SecurityNetty3Transport.profileSsl(profileSettings, settings)
|
||||
&& SecurityNetty3Transport.CLIENT_AUTH_SETTING.get(profileSettings, settings).enabled()) {
|
||||
if (SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings)
|
||||
&& sslService.isSSLClientAuthEnabled(
|
||||
SecurityNetty3Transport.profileSslSettings(profileSettings), transportSSLSettings)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.error("PKI realm [{}] is enabled but cannot be used as neither HTTP or Transport have both SSL and client authentication " +
|
||||
"enabled", config.name());
|
||||
throw new IllegalStateException("PKI realm [" + config.name() + "] is enabled but cannot be used as neither HTTP or Transport " +
|
||||
"has SSL with client authentication enabled");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.elasticsearch.rest.RestRequest;
|
|||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
||||
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
@ -32,6 +32,8 @@ import javax.net.ssl.SSLPeerUnverifiedException;
|
|||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -45,14 +47,15 @@ public class SecurityRestFilter extends RestFilter {
|
|||
|
||||
@Inject
|
||||
public SecurityRestFilter(AuthenticationService service, RestController controller, Settings settings,
|
||||
ThreadPool threadPool, XPackLicenseState licenseState) {
|
||||
ThreadPool threadPool, XPackLicenseState licenseState, SSLService sslService) {
|
||||
this.service = service;
|
||||
this.licenseState = licenseState;
|
||||
this.threadContext = threadPool.getThreadContext();
|
||||
this.logger = Loggers.getLogger(getClass(), settings);
|
||||
final boolean ssl = HTTP_SSL_ENABLED.get(settings);
|
||||
Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
this.extractClientCertificate = ssl && sslService.isSSLClientAuthEnabled(httpSSLSettings);
|
||||
controller.registerFilter(this);
|
||||
boolean ssl = SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings);
|
||||
extractClientCertificate = ssl && SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.get(settings).enabled();
|
||||
logger = Loggers.getLogger(getClass(), settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,447 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.support.OptionalSettings.createInt;
|
||||
import static org.elasticsearch.xpack.security.support.OptionalSettings.createString;
|
||||
import static org.elasticsearch.xpack.security.support.OptionalSettings.createTimeValue;
|
||||
|
||||
/**
|
||||
* Class that contains all configuration related to SSL use within x-pack
|
||||
*/
|
||||
abstract class SSLConfiguration {
|
||||
|
||||
abstract KeyConfig keyConfig();
|
||||
|
||||
abstract TrustConfig trustConfig();
|
||||
|
||||
abstract String protocol();
|
||||
|
||||
abstract int sessionCacheSize();
|
||||
|
||||
abstract TimeValue sessionCacheTimeout();
|
||||
|
||||
abstract List<String> ciphers();
|
||||
|
||||
abstract List<String> supportedProtocols();
|
||||
|
||||
/**
|
||||
* Provides the list of paths to files that back this configuration
|
||||
*/
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
if (keyConfig() == trustConfig()) {
|
||||
return keyConfig().filesToMonitor(environment);
|
||||
}
|
||||
List<Path> paths = new ArrayList<>(keyConfig().filesToMonitor(environment));
|
||||
paths.addAll(trustConfig().filesToMonitor(environment));
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SSLConfiguration)) return false;
|
||||
|
||||
SSLConfiguration that = (SSLConfiguration) o;
|
||||
|
||||
if (this.sessionCacheSize() != that.sessionCacheSize()) {
|
||||
return false;
|
||||
}
|
||||
if (this.keyConfig() != null ? !this.keyConfig().equals(that.keyConfig()) : that.keyConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.trustConfig() != null ? !this.trustConfig().equals(that.trustConfig()) : that.trustConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.protocol() != null ? !this.protocol().equals(that.protocol()) : that.protocol() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.sessionCacheTimeout() != null ?
|
||||
!this.sessionCacheTimeout().equals(that.sessionCacheTimeout()) : that.sessionCacheTimeout() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.ciphers() != null ? !this.ciphers().equals(that.ciphers()) : that.ciphers() != null) {
|
||||
return false;
|
||||
}
|
||||
return this.supportedProtocols() != null ?
|
||||
this.supportedProtocols().equals(that.supportedProtocols()) : that.supportedProtocols() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.keyConfig() != null ? this.keyConfig().hashCode() : 0;
|
||||
result = 31 * result + (this.trustConfig() != null ? this.trustConfig().hashCode() : 0);
|
||||
result = 31 * result + (this.protocol() != null ? this.protocol().hashCode() : 0);
|
||||
result = 31 * result + this.sessionCacheSize();
|
||||
result = 31 * result + (this.sessionCacheTimeout() != null ? this.sessionCacheTimeout().hashCode() : 0);
|
||||
result = 31 * result + (this.ciphers() != null ? this.ciphers().hashCode() : 0);
|
||||
result = 31 * result + (this.supportedProtocols() != null ? this.supportedProtocols().hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static class Global extends SSLConfiguration {
|
||||
|
||||
static final List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2");
|
||||
static final List<String> DEFAULT_CIPHERS =
|
||||
Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
|
||||
static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
|
||||
static final int DEFAULT_SESSION_CACHE_SIZE = 1000;
|
||||
static final String DEFAULT_PROTOCOL = "TLSv1.2";
|
||||
|
||||
// common settings
|
||||
static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting(globalKey(Custom.CIPHERS_SETTING), DEFAULT_CIPHERS,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING = Setting.listSetting(globalKey(Custom.SUPPORTED_PROTOCOLS_SETTING),
|
||||
DEFAULT_SUPPORTED_PROTOCOLS, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> PROTOCOL_SETTING = new Setting<>(globalKey(Custom.PROTOCOL_SETTING), DEFAULT_PROTOCOL,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Integer> SESSION_CACHE_SIZE_SETTING = Setting.intSetting(globalKey(Custom.CACHE_SIZE_SETTING),
|
||||
DEFAULT_SESSION_CACHE_SIZE, Property.NodeScope, Property.Filtered);
|
||||
static final Setting<TimeValue> SESSION_CACHE_TIMEOUT_SETTING = Setting.timeSetting(globalKey(Custom.CACHE_TIMEOUT_SETTING),
|
||||
DEFAULT_SESSION_CACHE_TIMEOUT, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// keystore settings
|
||||
static final Setting<Optional<String>> KEYSTORE_PATH_SETTING = createString(globalKey(Custom.KEYSTORE_PATH_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.keyStore"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = createString(globalKey(Custom.KEYSTORE_PASSWORD_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.keyStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.KEYSTORE_ALGORITHM_SETTING),
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
createString(globalKey(Custom.KEYSTORE_KEY_PASSWORD_SETTING), KEYSTORE_PASSWORD_SETTING,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
|
||||
// truststore settings
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = createString(globalKey(Custom.TRUSTSTORE_PATH_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.trustStore"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = createString(globalKey(Custom.TRUSTSTORE_PASSWORD_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.trustStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.TRUSTSTORE_ALGORITHM_SETTING),
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
|
||||
// PEM key and cert settings
|
||||
static final Setting<Optional<String>> KEY_PATH_SETTING = createString(globalKey(Custom.KEY_PATH_SETTING),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEY_PASSWORD_SETTING = createString(globalKey(Custom.KEY_PASSWORD_SETTING),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
static final Setting<List<String>> CERT_SETTING = Setting.listSetting(globalKey(Custom.CERT_SETTING), Collections.emptyList(),
|
||||
s -> s, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// PEM trusted certs
|
||||
static final Setting<List<String>> CA_PATHS_SETTING = Setting.listSetting(globalKey(Custom.CA_PATHS_SETTING),
|
||||
Collections.emptyList(), s -> s, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// Default system trusted certs
|
||||
static final Setting<Boolean> INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting(globalKey(Custom.INCLUDE_JDK_CERTS_SETTING), true,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
|
||||
private final KeyConfig keyConfig;
|
||||
private final TrustConfig trustConfig;
|
||||
private final String sslProtocol;
|
||||
private final int sessionCacheSize;
|
||||
private final TimeValue sessionCacheTimeout;
|
||||
private final List<String> ciphers;
|
||||
private final List<String> supportedProtocols;
|
||||
|
||||
/**
|
||||
* This constructor should be used with the global settings of the service
|
||||
*
|
||||
* @param settings the global settings to build the SSL configuration from
|
||||
*/
|
||||
Global(Settings settings) {
|
||||
this.keyConfig = createGlobalKeyConfig(settings);
|
||||
this.trustConfig = createGlobalTrustConfig(settings, keyConfig);
|
||||
this.sslProtocol = PROTOCOL_SETTING.get(settings);
|
||||
this.sessionCacheSize = SESSION_CACHE_SIZE_SETTING.get(settings);
|
||||
this.sessionCacheTimeout = SESSION_CACHE_TIMEOUT_SETTING.get(settings);
|
||||
this.ciphers = CIPHERS_SETTING.get(settings);
|
||||
this.supportedProtocols = SUPPORTED_PROTOCOLS_SETTING.get(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
KeyConfig keyConfig() {
|
||||
return keyConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
TrustConfig trustConfig() {
|
||||
return trustConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
String protocol() {
|
||||
return sslProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
int sessionCacheSize() {
|
||||
return sessionCacheSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
TimeValue sessionCacheTimeout() {
|
||||
return sessionCacheTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<String> ciphers() {
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<String> supportedProtocols() {
|
||||
return supportedProtocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLConfiguration{" +
|
||||
"keyConfig=[" + keyConfig +
|
||||
"], trustConfig=" + trustConfig +
|
||||
"], sslProtocol=['" + sslProtocol + '\'' +
|
||||
"], sessionCacheSize=[" + sessionCacheSize +
|
||||
"], sessionCacheTimeout=[" + sessionCacheTimeout +
|
||||
"], ciphers=[" + ciphers +
|
||||
"], supportedProtocols=[" + supportedProtocols +
|
||||
"]}";
|
||||
}
|
||||
|
||||
private static String globalKey(Setting setting) {
|
||||
return setting("ssl." + setting.getKey());
|
||||
}
|
||||
|
||||
static KeyConfig createGlobalKeyConfig(Settings settings) {
|
||||
String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
String keyPath = KEY_PATH_SETTING.get(settings).orElse(null);
|
||||
if (keyPath != null && keyStorePath != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a keystore and key file");
|
||||
} else if (keyStorePath == null && keyPath == null) {
|
||||
return KeyConfig.NONE;
|
||||
}
|
||||
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
if (keyPath != null) {
|
||||
String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
List<String> certPaths = getListOrNull(CERT_SETTING, settings);
|
||||
if (certPaths == null) {
|
||||
throw new IllegalArgumentException("you must specify the certificates to use with the key");
|
||||
}
|
||||
return new PEMKeyConfig(includeSystem, keyPath, keyPassword, certPaths);
|
||||
} else {
|
||||
assert keyStorePath != null;
|
||||
String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings);
|
||||
String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreKeyConfig(includeSystem, keyStorePath, keyStorePassword, keyStoreKeyPassword,
|
||||
keyStoreAlgorithm, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
static TrustConfig createGlobalTrustConfig(Settings settings, KeyConfig keyInfo) {
|
||||
String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
List<String> caPaths = getListOrNull(CA_PATHS_SETTING, settings);
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
if (trustStorePath != null && caPaths != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
|
||||
} else if (caPaths != null) {
|
||||
return new PEMTrustConfig(includeSystem, caPaths);
|
||||
} else if (trustStorePath != null) {
|
||||
String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreTrustConfig(includeSystem, trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
} else if (keyInfo != KeyConfig.NONE) {
|
||||
return keyInfo;
|
||||
} else {
|
||||
return new StoreTrustConfig(includeSystem, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Custom extends SSLConfiguration {
|
||||
|
||||
static final Setting<Optional<String>> PROTOCOL_SETTING = createString("protocol");
|
||||
static final Setting<Optional<Integer>> CACHE_SIZE_SETTING = createInt("session.cache_size");
|
||||
static final Setting<Optional<TimeValue>> CACHE_TIMEOUT_SETTING = createTimeValue("session.cache_timeout");
|
||||
static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting("ciphers", Collections.emptyList(), s -> s);
|
||||
static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting("supported_protocols", Collections.emptyList(), s -> s);
|
||||
|
||||
static final Setting<Optional<String>> KEYSTORE_PATH_SETTING = createString("keystore.path");
|
||||
static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = createString("keystore.password");
|
||||
static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>("keystore.algorithm",
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_FALLBACK = createString("keystore.password");
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
createString("keystore.key_password", KEYSTORE_KEY_PASSWORD_FALLBACK);
|
||||
|
||||
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = createString("truststore.path");
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = createString("truststore.password");
|
||||
static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("truststore.algorithm",
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm",
|
||||
TrustManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
|
||||
static final Setting<Optional<String>> KEY_PATH_SETTING = createString("key.path");
|
||||
static final Setting<Optional<String>> KEY_PASSWORD_SETTING = createString("key.password");
|
||||
static final Setting<List<String>> CERT_SETTING = Setting.listSetting("cert", Collections.emptyList(), s -> s);
|
||||
|
||||
static final Setting<List<String>> CA_PATHS_SETTING = Setting.listSetting("ca", Collections.emptyList(), s -> s);
|
||||
static final Setting<Boolean> INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting("trust_cacerts", true);
|
||||
|
||||
private final KeyConfig keyConfig;
|
||||
private final TrustConfig trustConfig;
|
||||
private final String sslProtocol;
|
||||
private final int sessionCacheSize;
|
||||
private final TimeValue sessionCacheTimeout;
|
||||
private final List<String> ciphers;
|
||||
private final List<String> supportedProtocols;
|
||||
|
||||
/**
|
||||
* The settings passed in should be the group settings under ssl, like xpack.security.ssl
|
||||
*
|
||||
* @param settings the profile settings to get the SSL configuration for
|
||||
* @param defaultConfig the default SSL configuration
|
||||
*/
|
||||
Custom(Settings settings, SSLConfiguration defaultConfig) {
|
||||
Objects.requireNonNull(settings);
|
||||
this.keyConfig = createKeyConfig(settings, defaultConfig);
|
||||
this.trustConfig = createTrustConfig(settings, keyConfig, defaultConfig);
|
||||
this.sslProtocol = PROTOCOL_SETTING.get(settings).orElse(defaultConfig.protocol());
|
||||
this.sessionCacheSize = CACHE_SIZE_SETTING.get(settings).orElse(defaultConfig.sessionCacheSize());
|
||||
this.sessionCacheTimeout = CACHE_TIMEOUT_SETTING.get(settings).orElse(defaultConfig.sessionCacheTimeout());
|
||||
this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, defaultConfig.ciphers());
|
||||
this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, defaultConfig.supportedProtocols());
|
||||
}
|
||||
|
||||
@Override
|
||||
KeyConfig keyConfig() {
|
||||
return keyConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
TrustConfig trustConfig() {
|
||||
return trustConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
String protocol() {
|
||||
return sslProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
int sessionCacheSize() {
|
||||
return sessionCacheSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
TimeValue sessionCacheTimeout() {
|
||||
return sessionCacheTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<String> ciphers() {
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<String> supportedProtocols() {
|
||||
return supportedProtocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLConfiguration{" +
|
||||
"keyConfig=[" + keyConfig +
|
||||
"], trustConfig=" + trustConfig +
|
||||
"], sslProtocol=['" + sslProtocol + '\'' +
|
||||
"], sessionCacheSize=[" + sessionCacheSize +
|
||||
"], sessionCacheTimeout=[" + sessionCacheTimeout +
|
||||
"], ciphers=[" + ciphers +
|
||||
"], supportedProtocols=[" + supportedProtocols +
|
||||
'}';
|
||||
}
|
||||
|
||||
static KeyConfig createKeyConfig(Settings settings, SSLConfiguration global) {
|
||||
String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
String keyPath = KEY_PATH_SETTING.get(settings).orElse(null);
|
||||
if (keyPath != null && keyStorePath != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a keystore and key file");
|
||||
} else if (keyStorePath == null && keyPath == null) {
|
||||
return global.keyConfig();
|
||||
}
|
||||
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
if (keyPath != null) {
|
||||
String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
List<String> certPaths = getListOrNull(CERT_SETTING, settings);
|
||||
if (certPaths == null) {
|
||||
throw new IllegalArgumentException("you must specify the certificates to use with the key");
|
||||
}
|
||||
return new PEMKeyConfig(includeSystem, keyPath, keyPassword, certPaths);
|
||||
} else {
|
||||
assert keyStorePath != null;
|
||||
String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings);
|
||||
String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreKeyConfig(includeSystem, keyStorePath, keyStorePassword, keyStoreKeyPassword,
|
||||
keyStoreAlgorithm, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
static TrustConfig createTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) {
|
||||
String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
List<String> caPaths = getListOrNull(CA_PATHS_SETTING, settings);
|
||||
if (trustStorePath != null && caPaths != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
|
||||
} else if (caPaths != null) {
|
||||
return new PEMTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings), caPaths);
|
||||
} else if (trustStorePath != null) {
|
||||
String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings),
|
||||
trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
} else if (keyConfig == global.keyConfig()) {
|
||||
return global.trustConfig();
|
||||
} else {
|
||||
return keyConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> getListOrNull(Setting<List<String>> listSetting, Settings settings) {
|
||||
return getListOrDefault(listSetting, settings, null);
|
||||
}
|
||||
|
||||
static List<String> getListOrDefault(Setting<List<String>> listSetting, Settings settings, List<String> defaultValue) {
|
||||
if (listSetting.exists(settings)) {
|
||||
return listSetting.get(settings);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
|
||||
abstract class TrustConfig {
|
||||
|
||||
protected final boolean includeSystem;
|
||||
|
||||
TrustConfig(boolean includeSystem) {
|
||||
this.includeSystem = includeSystem;
|
||||
}
|
||||
|
||||
final X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager trustManager = nonSystemTrustManager(environment);
|
||||
if (includeSystem) {
|
||||
trustManager = mergeWithSystem(trustManager);
|
||||
} else if (trustManager == null) {
|
||||
return null;
|
||||
}
|
||||
return trustManager;
|
||||
}
|
||||
|
||||
abstract X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment);
|
||||
|
||||
abstract void validate();
|
||||
|
||||
abstract List<Path> filesToMonitor(@Nullable Environment environment);
|
||||
|
||||
public abstract String toString();
|
||||
|
||||
private X509ExtendedTrustManager mergeWithSystem(X509ExtendedTrustManager nonSystemTrustManager) {
|
||||
try {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init((KeyStore) null);
|
||||
TrustManager[] systemTrustManagers = tmf.getTrustManagers();
|
||||
X509ExtendedTrustManager system = findFirstX509ExtendedTrustManager(systemTrustManagers);
|
||||
if (nonSystemTrustManager == null) {
|
||||
return system;
|
||||
}
|
||||
|
||||
return new CombiningX509TrustManager(nonSystemTrustManager, system);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a trust managers", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509ExtendedTrustManager findFirstX509ExtendedTrustManager(TrustManager[] trustManagers) {
|
||||
X509ExtendedTrustManager x509TrustManager = null;
|
||||
for (TrustManager trustManager : trustManagers) {
|
||||
if (trustManager instanceof X509ExtendedTrustManager) {
|
||||
// first one wins like in the JDK
|
||||
x509TrustManager = (X509ExtendedTrustManager) trustManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x509TrustManager == null) {
|
||||
throw new IllegalArgumentException("did not find a X509ExtendedTrustManager");
|
||||
}
|
||||
return x509TrustManager;
|
||||
}
|
||||
|
||||
private static class CombiningX509TrustManager extends X509ExtendedTrustManager {
|
||||
|
||||
private final X509ExtendedTrustManager first;
|
||||
private final X509ExtendedTrustManager second;
|
||||
|
||||
private final X509Certificate[] acceptedIssuers;
|
||||
|
||||
CombiningX509TrustManager(X509ExtendedTrustManager first, X509ExtendedTrustManager second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
X509Certificate[] firstIssuers = first.getAcceptedIssuers();
|
||||
X509Certificate[] secondIssuers = second.getAcceptedIssuers();
|
||||
this.acceptedIssuers = new X509Certificate[firstIssuers.length + secondIssuers.length];
|
||||
System.arraycopy(firstIssuers, 0, acceptedIssuers, 0, firstIssuers.length);
|
||||
System.arraycopy(secondIssuers, 0, acceptedIssuers, firstIssuers.length, secondIssuers.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s, socket);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s, socket);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s, sslEngine);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s, sslEngine);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return acceptedIssuers;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.support;
|
||||
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class OptionalSettings {
|
||||
|
||||
private OptionalSettings() {}
|
||||
|
||||
public static Setting<Optional<Integer>> createInt(String key, Property... properties) {
|
||||
return new Setting<>(key, s -> null, s -> {
|
||||
if (s != null) {
|
||||
return Optional.of(Integer.parseInt(s));
|
||||
} else {
|
||||
return Optional.<Integer>ofNullable(null);
|
||||
}
|
||||
}, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Property... properties) {
|
||||
return createString(key, s -> null, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Function<Settings, String> defaultValue, Property... properties) {
|
||||
return new Setting<>(key, defaultValue, Optional::ofNullable, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Setting<Optional<String>> fallback, Property... properties) {
|
||||
return new Setting<>(key, fallback, Optional::ofNullable, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<TimeValue>> createTimeValue(String key, Property... properties) {
|
||||
return new Setting<>(key, s-> null, s -> {
|
||||
if (s != null) {
|
||||
return Optional.of(TimeValue.parseTimeValue(s, key));
|
||||
} else {
|
||||
return Optional.<TimeValue>ofNullable(null);
|
||||
}
|
||||
}, properties);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.xpack.security.authz.AuthorizationService;
|
|||
import org.elasticsearch.xpack.security.authz.AuthorizationUtils;
|
||||
import org.elasticsearch.xpack.security.authz.accesscontrol.RequestContext;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
@ -36,32 +37,33 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.CLIENT_AUTH_SETTING;
|
||||
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING;
|
||||
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.SSL_SETTING;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
|
||||
public class SecurityServerTransportService extends TransportService {
|
||||
|
||||
public static final String SETTING_NAME = "xpack.security.type";
|
||||
private static final String SETTING_NAME = "xpack.security.type";
|
||||
|
||||
protected final AuthenticationService authcService;
|
||||
protected final AuthorizationService authzService;
|
||||
protected final SecurityActionMapper actionMapper;
|
||||
protected final XPackLicenseState licenseState;
|
||||
|
||||
protected final Map<String, ServerTransportFilter> profileFilters;
|
||||
private final AuthenticationService authcService;
|
||||
private final AuthorizationService authzService;
|
||||
private final SecurityActionMapper actionMapper;
|
||||
private final SSLService sslService;
|
||||
private final Map<String, ServerTransportFilter> profileFilters;
|
||||
final XPackLicenseState licenseState;
|
||||
|
||||
@Inject
|
||||
public SecurityServerTransportService(Settings settings, Transport transport, ThreadPool threadPool,
|
||||
AuthenticationService authcService,
|
||||
AuthorizationService authzService,
|
||||
SecurityActionMapper actionMapper,
|
||||
XPackLicenseState licenseState) {
|
||||
XPackLicenseState licenseState,
|
||||
SSLService sslService) {
|
||||
super(settings, transport, threadPool);
|
||||
this.authcService = authcService;
|
||||
this.authzService = authzService;
|
||||
this.actionMapper = actionMapper;
|
||||
this.licenseState = licenseState;
|
||||
this.sslService = sslService;
|
||||
this.profileFilters = initializeProfileFilters();
|
||||
}
|
||||
|
||||
|
@ -119,10 +121,12 @@ public class SecurityServerTransportService extends TransportService {
|
|||
Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true);
|
||||
Map<String, ServerTransportFilter> profileFilters = new HashMap<>(profileSettingsMap.size() + 1);
|
||||
|
||||
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
|
||||
Settings profileSettings = entry.getValue();
|
||||
final boolean profileSsl = SecurityNetty3Transport.profileSsl(profileSettings, settings);
|
||||
final boolean clientAuth = PROFILE_CLIENT_AUTH_SETTING.get(profileSettings, settings).enabled();
|
||||
final boolean profileSsl = SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings);
|
||||
final Settings profileSslSettings = SecurityNetty3Transport.profileSslSettings(profileSettings);
|
||||
final boolean clientAuth = sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings);
|
||||
final boolean extractClientCert = profileSsl && clientAuth;
|
||||
String type = entry.getValue().get(SETTING_NAME, "node");
|
||||
switch (type) {
|
||||
|
@ -137,8 +141,8 @@ public class SecurityServerTransportService extends TransportService {
|
|||
}
|
||||
|
||||
if (!profileFilters.containsKey(TransportSettings.DEFAULT_PROFILE)) {
|
||||
final boolean profileSsl = SSL_SETTING.get(settings);
|
||||
final boolean clientAuth = CLIENT_AUTH_SETTING.get(settings).enabled();
|
||||
final boolean profileSsl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
final boolean clientAuth = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
||||
final boolean extractClientCert = profileSsl && clientAuth;
|
||||
profileFilters.put(TransportSettings.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
|
||||
actionMapper, threadPool.getThreadContext(), extractClientCert));
|
||||
|
@ -159,9 +163,9 @@ public class SecurityServerTransportService extends TransportService {
|
|||
private final XPackLicenseState licenseState;
|
||||
private final ThreadContext threadContext;
|
||||
|
||||
public ProfileSecuredRequestHandler(String action, TransportRequestHandler<T> handler,
|
||||
Map<String, ServerTransportFilter> profileFilters, XPackLicenseState licenseState,
|
||||
ThreadContext threadContext) {
|
||||
private ProfileSecuredRequestHandler(String action, TransportRequestHandler<T> handler,
|
||||
Map<String,ServerTransportFilter> profileFilters, XPackLicenseState licenseState,
|
||||
ThreadContext threadContext) {
|
||||
this.action = action;
|
||||
this.handler = handler;
|
||||
this.profileFilters = profileFilters;
|
||||
|
|
|
@ -9,14 +9,11 @@ import org.apache.logging.log4j.message.ParameterizedMessage;
|
|||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.http.netty3.Netty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
|
@ -25,45 +22,28 @@ import org.jboss.netty.channel.ExceptionEvent;
|
|||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport {
|
||||
|
||||
public static final boolean SSL_DEFAULT = false;
|
||||
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.NO.name();
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
|
||||
Setting.boolSetting(setting("http.ssl"), SSL_DEFAULT, Property.NodeScope, Property.Deprecated);
|
||||
public static final Setting<Boolean> SSL_SETTING =
|
||||
Setting.boolSetting(setting("http.ssl.enabled"), DEPRECATED_SSL_SETTING, Property.NodeScope);
|
||||
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
|
||||
new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope);
|
||||
|
||||
private final IPFilter ipFilter;
|
||||
private final SSLService sslService;
|
||||
private final boolean ssl;
|
||||
private final Settings sslSettings;
|
||||
|
||||
@Inject
|
||||
public SecurityNetty3HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter,
|
||||
SSLService sslService, ThreadPool threadPool) {
|
||||
super(settings, networkService, bigArrays, threadPool);
|
||||
this.ipFilter = ipFilter;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.sslService = sslService;
|
||||
if (ssl) {
|
||||
sslSettings = settings.getByPrefix(setting("http.ssl."));
|
||||
} else {
|
||||
sslSettings = Settings.EMPTY;
|
||||
}
|
||||
this.ssl = HTTP_SSL_ENABLED.get(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,13 +89,14 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport
|
|||
|
||||
private class HttpSslChannelPipelineFactory extends HttpChannelPipelineFactory {
|
||||
|
||||
private final SSLClientAuth clientAuth;
|
||||
private final Settings sslSettings;
|
||||
|
||||
public HttpSslChannelPipelineFactory(Netty3HttpServerTransport transport) {
|
||||
super(transport, detailedErrorsEnabled, threadPool.getThreadContext());
|
||||
clientAuth = CLIENT_AUTH_SETTING.get(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server");
|
||||
this.sslSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " +
|
||||
"[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,10 +104,7 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport
|
|||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (ssl) {
|
||||
SSLEngine engine = sslService.createSSLEngine(sslSettings);
|
||||
engine.setUseClientMode(false);
|
||||
clientAuth.configure(engine);
|
||||
|
||||
SSLEngine engine = sslService.createSSLEngine(sslSettings, Settings.EMPTY);
|
||||
pipeline.addFirst("ssl", new SslHandler(engine));
|
||||
}
|
||||
pipeline.addFirst("ipfilter", new IPFilterNetty3UpstreamHandler(ipFilter, IPFilter.HTTP_PROFILE_NAME));
|
||||
|
@ -134,14 +112,8 @@ public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport
|
|||
}
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settings) {
|
||||
settings.add(SSL_SETTING);
|
||||
settings.add(CLIENT_AUTH_SETTING);
|
||||
settings.add(DEPRECATED_SSL_SETTING);
|
||||
}
|
||||
|
||||
public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) {
|
||||
if (SSL_SETTING.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) {
|
||||
if (HTTP_SSL_ENABLED.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) {
|
||||
settingsBuilder.put(SETTING_HTTP_COMPRESSION.getKey(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,20 +7,18 @@ package org.elasticsearch.xpack.security.transport.netty3;
|
|||
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty3.Netty3Transport;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
|
@ -31,69 +29,21 @@ import org.jboss.netty.channel.SimpleChannelHandler;
|
|||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.Security.settingPrefix;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
public class SecurityNetty3Transport extends Netty3Transport {
|
||||
|
||||
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name();
|
||||
public static final boolean SSL_DEFAULT = false;
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("ssl.hostname_verification"),
|
||||
true,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(setting("ssl.hostname_verification.enabled"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING,
|
||||
Property.NodeScope, Property.Filtered, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("ssl.hostname_verification.resolve_name"),
|
||||
true,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
|
||||
Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT,
|
||||
Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> SSL_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("transport.ssl.enabled"),
|
||||
DEPRECATED_SSL_SETTING,
|
||||
new Property[]{Property.Filtered, Property.NodeScope, Property.Shared});
|
||||
|
||||
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
|
||||
new Setting<>(
|
||||
setting("transport.ssl.client.auth"),
|
||||
CLIENT_AUTH_DEFAULT,
|
||||
SSLClientAuth::parse,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_PROFILE_SSL_SETTING =
|
||||
Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> PROFILE_SSL_SETTING =
|
||||
Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared);
|
||||
|
||||
public static final Setting<SSLClientAuth> PROFILE_CLIENT_AUTH_SETTING =
|
||||
new Setting<>(
|
||||
setting("ssl.client.auth"),
|
||||
CLIENT_AUTH_SETTING,
|
||||
SSLClientAuth::parse,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
public static final Setting<Boolean> PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false);
|
||||
|
||||
private final SSLService sslService;
|
||||
@Nullable private final IPFilter authenticator;
|
||||
private final Settings transportSSLSettings;
|
||||
private final boolean ssl;
|
||||
|
||||
@Inject
|
||||
|
@ -102,8 +52,10 @@ public class SecurityNetty3Transport extends Netty3Transport {
|
|||
CircuitBreakerService circuitBreakerService) {
|
||||
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
|
||||
this.authenticator = authenticator;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.ssl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
this.sslService = sslService;
|
||||
this.transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,42 +99,36 @@ public class SecurityNetty3Transport extends Netty3Transport {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean profileSsl(Settings profileSettings, Settings settings) {
|
||||
// we can't use the fallback mechanism here since it may not exist in the profile settings and we get the wrong value
|
||||
// for the profile if they use the old setting
|
||||
if (PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else if (DEPRECATED_PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return DEPRECATED_PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else {
|
||||
return SSL_SETTING.get(settings);
|
||||
}
|
||||
public static Settings profileSslSettings(Settings profileSettings) {
|
||||
return profileSettings.getByPrefix(setting("ssl."));
|
||||
}
|
||||
|
||||
private class SslServerChannelPipelineFactory extends ServerChannelPipelineFactory {
|
||||
|
||||
private final boolean sslEnabled;
|
||||
private final Settings securityProfileSettings;
|
||||
private final SSLClientAuth sslClientAuth;
|
||||
private final boolean profileSsl;
|
||||
private final Settings profileSslSettings;
|
||||
|
||||
public SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) {
|
||||
SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) {
|
||||
super(nettyTransport, name, settings);
|
||||
this.sslEnabled = profileSsl(profileSettings, settings);
|
||||
this.securityProfileSettings = profileSettings.getByPrefix(settingPrefix());
|
||||
this.sslClientAuth = PROFILE_CLIENT_AUTH_SETTING.get(profileSettings, settings);
|
||||
if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server");
|
||||
this.profileSsl = PROFILE_SSL_SETTING.exists(profileSettings) ? PROFILE_SSL_SETTING.get(profileSettings) : ssl;
|
||||
this.profileSslSettings = profileSslSettings(profileSettings);
|
||||
if (profileSsl && sslService.isConfigurationValidForServerUsage(profileSslSettings, transportSSLSettings) == false) {
|
||||
if (TransportSettings.DEFAULT_PROFILE.equals(name)) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[xpack.security.transport.ssl.key] or [xpack.security.transport.ssl.keystore.path] setting");
|
||||
}
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[transport.profiles." + name + ".xpack.security.ssl.key] or [transport.profiles." + name
|
||||
+ ".xpack.security.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (sslEnabled) {
|
||||
SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings);
|
||||
if (profileSsl) {
|
||||
final SSLEngine serverEngine = sslService.createSSLEngine(profileSslSettings, transportSSLSettings);
|
||||
serverEngine.setUseClientMode(false);
|
||||
sslClientAuth.configure(serverEngine);
|
||||
|
||||
pipeline.addFirst("ssl", new SslHandler(serverEngine));
|
||||
}
|
||||
if (authenticator != null) {
|
||||
|
@ -194,8 +140,12 @@ public class SecurityNetty3Transport extends Netty3Transport {
|
|||
|
||||
private class SslClientChannelPipelineFactory extends ClientChannelPipelineFactory {
|
||||
|
||||
public SslClientChannelPipelineFactory(Netty3Transport transport) {
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
|
||||
SslClientChannelPipelineFactory(Netty3Transport transport) {
|
||||
super(transport);
|
||||
this.hostnameVerificationEnabled =
|
||||
sslService.getVerificationMode(transportSSLSettings, Settings.EMPTY).isHostnameVerificationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -216,19 +166,13 @@ public class SecurityNetty3Transport extends Netty3Transport {
|
|||
@Override
|
||||
public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) {
|
||||
SSLEngine sslEngine;
|
||||
if (HOSTNAME_VERIFICATION_SETTING.get(settings)) {
|
||||
if (hostnameVerificationEnabled) {
|
||||
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();
|
||||
sslEngine = sslService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress),
|
||||
// we create the socket based on the name given. don't reverse DNS
|
||||
sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY, inetSocketAddress.getHostString(),
|
||||
inetSocketAddress.getPort());
|
||||
|
||||
// By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification
|
||||
// we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against
|
||||
// man in the middle attacks for transport connections
|
||||
SSLParameters parameters = new SSLParameters();
|
||||
parameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
sslEngine.setSSLParameters(parameters);
|
||||
} else {
|
||||
sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY);
|
||||
}
|
||||
|
||||
sslEngine.setUseClientMode(true);
|
||||
|
@ -237,36 +181,6 @@ public class SecurityNetty3Transport extends Netty3Transport {
|
|||
|
||||
ctx.sendDownstream(e);
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "need to use getHostName to resolve DNS name for SSL connections and hostname verification")
|
||||
private String getHostname(InetSocketAddress inetSocketAddress) {
|
||||
String hostname;
|
||||
if (HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.get(settings)) {
|
||||
hostname = inetSocketAddress.getHostName();
|
||||
} else {
|
||||
hostname = inetSocketAddress.getHostString();
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("resolved hostname [{}] for address [{}] to be used in ssl hostname verification", hostname,
|
||||
inetSocketAddress);
|
||||
}
|
||||
return hostname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settingsModule) {
|
||||
settingsModule.add(SSL_SETTING);
|
||||
settingsModule.add(HOSTNAME_VERIFICATION_SETTING);
|
||||
settingsModule.add(HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING);
|
||||
settingsModule.add(CLIENT_AUTH_SETTING);
|
||||
settingsModule.add(PROFILE_SSL_SETTING);
|
||||
settingsModule.add(PROFILE_CLIENT_AUTH_SETTING);
|
||||
|
||||
// deprecated transport settings
|
||||
settingsModule.add(DEPRECATED_SSL_SETTING);
|
||||
settingsModule.add(DEPRECATED_PROFILE_SSL_SETTING);
|
||||
settingsModule.add(DEPRECATED_HOSTNAME_VERIFICATION_SETTING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,53 +13,33 @@ import org.apache.logging.log4j.message.ParameterizedMessage;
|
|||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.http.netty4.Netty4HttpServerTransport;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
|
||||
public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport {
|
||||
|
||||
public static final boolean SSL_DEFAULT = false;
|
||||
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.NO.name();
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
|
||||
Setting.boolSetting(setting("http.ssl"), SSL_DEFAULT, Property.NodeScope, Property.Deprecated);
|
||||
public static final Setting<Boolean> SSL_SETTING =
|
||||
Setting.boolSetting(setting("http.ssl.enabled"), DEPRECATED_SSL_SETTING, Property.NodeScope);
|
||||
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
|
||||
new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope);
|
||||
|
||||
private final IPFilter ipFilter;
|
||||
private final SSLService sslService;
|
||||
private final boolean ssl;
|
||||
private final Settings sslSettings;
|
||||
|
||||
@Inject
|
||||
public SecurityNetty4HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter,
|
||||
SSLService sslService, ThreadPool threadPool) {
|
||||
super(settings, networkService, bigArrays, threadPool);
|
||||
this.ipFilter = ipFilter;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.ssl = HTTP_SSL_ENABLED.get(settings);
|
||||
this.sslService = sslService;
|
||||
if (ssl) {
|
||||
sslSettings = settings.getByPrefix(setting("http.ssl."));
|
||||
} else {
|
||||
sslSettings = Settings.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,13 +84,14 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
|
|||
|
||||
private class HttpSslChannelHandler extends HttpChannelHandler {
|
||||
|
||||
private final SSLClientAuth clientAuth;
|
||||
private final Settings sslSettings;
|
||||
|
||||
HttpSslChannelHandler(Netty4HttpServerTransport transport) {
|
||||
super(transport, detailedErrorsEnabled, threadPool.getThreadContext());
|
||||
clientAuth = CLIENT_AUTH_SETTING.get(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server");
|
||||
this.sslSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " +
|
||||
"[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,9 +99,8 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
|
|||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
if (ssl) {
|
||||
final SSLEngine engine = sslService.createSSLEngine(sslSettings);
|
||||
final SSLEngine engine = sslService.createSSLEngine(sslSettings, Settings.EMPTY);
|
||||
engine.setUseClientMode(false);
|
||||
clientAuth.configure(engine);
|
||||
ch.pipeline().addFirst("ssl", new SslHandler(engine));
|
||||
}
|
||||
ch.pipeline().addFirst("ip_filter", new IpFilterRemoteAddressFilter(ipFilter, IPFilter.HTTP_PROFILE_NAME));
|
||||
|
@ -128,14 +108,8 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
|
|||
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settings) {
|
||||
settings.add(SSL_SETTING);
|
||||
settings.add(CLIENT_AUTH_SETTING);
|
||||
settings.add(DEPRECATED_SSL_SETTING);
|
||||
}
|
||||
|
||||
public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) {
|
||||
if (SSL_SETTING.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) {
|
||||
if (HTTP_SSL_ENABLED.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) {
|
||||
settingsBuilder.put(SETTING_HTTP_COMPRESSION.getKey(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,30 +11,27 @@ import io.netty.channel.ChannelHandlerContext;
|
|||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.transport.netty4.Netty4Transport;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.Security.settingPrefix;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -42,58 +39,11 @@ import static org.elasticsearch.xpack.security.Security.settingPrefix;
|
|||
*/
|
||||
public class SecurityNetty4Transport extends Netty4Transport {
|
||||
|
||||
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name();
|
||||
public static final boolean SSL_DEFAULT = false;
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("ssl.hostname_verification"),
|
||||
true,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(setting("ssl.hostname_verification.enabled"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING,
|
||||
Property.NodeScope, Property.Filtered, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("ssl.hostname_verification.resolve_name"),
|
||||
true,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
|
||||
Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT,
|
||||
Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> SSL_SETTING =
|
||||
Setting.boolSetting(
|
||||
setting("transport.ssl.enabled"),
|
||||
DEPRECATED_SSL_SETTING,
|
||||
new Property[]{Property.Filtered, Property.NodeScope, Property.Shared});
|
||||
|
||||
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
|
||||
new Setting<>(
|
||||
setting("transport.ssl.client.auth"),
|
||||
CLIENT_AUTH_DEFAULT,
|
||||
SSLClientAuth::parse,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_PROFILE_SSL_SETTING =
|
||||
Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
|
||||
|
||||
public static final Setting<Boolean> PROFILE_SSL_SETTING =
|
||||
Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared);
|
||||
|
||||
public static final Setting<SSLClientAuth> PROFILE_CLIENT_AUTH_SETTING =
|
||||
new Setting<>(
|
||||
setting("ssl.client.auth"),
|
||||
CLIENT_AUTH_SETTING,
|
||||
SSLClientAuth::parse,
|
||||
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
|
||||
private static final Setting<Boolean> PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false);
|
||||
|
||||
private final SSLService sslService;
|
||||
@Nullable private final IPFilter authenticator;
|
||||
private final SSLClientAuth clientAuth;
|
||||
private final Settings transportSSLSettings;
|
||||
private final boolean ssl;
|
||||
|
||||
@Inject
|
||||
|
@ -102,9 +52,9 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
@Nullable IPFilter authenticator, SSLService sslService) {
|
||||
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
|
||||
this.authenticator = authenticator;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.clientAuth = CLIENT_AUTH_SETTING.get(settings);
|
||||
this.ssl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
this.sslService = sslService;
|
||||
this.transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,12 +80,18 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
private final boolean sslEnabled;
|
||||
private final Settings securityProfileSettings;
|
||||
|
||||
protected SecurityServerChannelInitializer(String name, Settings settings) {
|
||||
super(name, settings);
|
||||
this.sslEnabled = profileSSL(settings, ssl);
|
||||
this.securityProfileSettings = settings.getByPrefix(settingPrefix());
|
||||
if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server");
|
||||
SecurityServerChannelInitializer(String name, Settings profileSettings) {
|
||||
super(name, profileSettings);
|
||||
this.sslEnabled = PROFILE_SSL_SETTING.exists(profileSettings) ? PROFILE_SSL_SETTING.get(profileSettings) : ssl;
|
||||
this.securityProfileSettings = profileSettings.getByPrefix(setting("ssl."));
|
||||
if (sslEnabled && sslService.isConfigurationValidForServerUsage(securityProfileSettings, transportSSLSettings) == false) {
|
||||
if (TransportSettings.DEFAULT_PROFILE.equals(name)) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[xpack.security.transport.ssl.key] or [xpack.security.transport.ssl.keystore.path] setting");
|
||||
}
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[transport.profiles." + name + ".xpack.security.ssl.key] or [transport.profiles." + name
|
||||
+ ".xpack.security.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,10 +99,8 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
if (sslEnabled) {
|
||||
SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings);
|
||||
SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings, transportSSLSettings);
|
||||
serverEngine.setUseClientMode(false);
|
||||
final SSLClientAuth profileClientAuth = profileClientAuth(settings, clientAuth);
|
||||
profileClientAuth.configure(serverEngine);
|
||||
ch.pipeline().addFirst(new SslHandler(serverEngine));
|
||||
}
|
||||
if (authenticator != null) {
|
||||
|
@ -155,72 +109,52 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
}
|
||||
}
|
||||
|
||||
class SecurityClientChannelInitializer extends ClientChannelInitializer {
|
||||
private class SecurityClientChannelInitializer extends ClientChannelInitializer {
|
||||
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
|
||||
SecurityClientChannelInitializer() {
|
||||
this.hostnameVerificationEnabled =
|
||||
sslService.getVerificationMode(transportSSLSettings, Settings.EMPTY).isHostnameVerificationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
if (ssl) {
|
||||
ch.pipeline().addFirst(new ClientSslHandlerInitializer());
|
||||
ch.pipeline().addFirst(new ClientSslHandlerInitializer(transportSSLSettings, sslService, hostnameVerificationEnabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClientSslHandlerInitializer extends ChannelOutboundHandlerAdapter {
|
||||
private static class ClientSslHandlerInitializer extends ChannelOutboundHandlerAdapter {
|
||||
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
private final Settings sslSettings;
|
||||
private final SSLService sslService;
|
||||
|
||||
private ClientSslHandlerInitializer(Settings sslSettings, SSLService sslService, boolean hostnameVerificationEnabled) {
|
||||
this.sslSettings = sslSettings;
|
||||
this.hostnameVerificationEnabled = hostnameVerificationEnabled;
|
||||
this.sslService = sslService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
|
||||
SocketAddress localAddress, ChannelPromise promise) throws Exception {
|
||||
final SSLEngine sslEngine;
|
||||
if (HOSTNAME_VERIFICATION_SETTING.get(settings)) {
|
||||
if (hostnameVerificationEnabled) {
|
||||
InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress;
|
||||
sslEngine = sslService.createSSLEngine(Settings.EMPTY, getHostname(inetSocketAddress), inetSocketAddress.getPort());
|
||||
|
||||
// By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification
|
||||
// we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against
|
||||
// man in the middle attacks for transport connections
|
||||
SSLParameters parameters = new SSLParameters();
|
||||
parameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
sslEngine.setSSLParameters(parameters);
|
||||
// we create the socket based on the name given. don't reverse DNS
|
||||
sslEngine = sslService.createSSLEngine(sslSettings, Settings.EMPTY, inetSocketAddress.getHostString(),
|
||||
inetSocketAddress.getPort());
|
||||
} else {
|
||||
sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
sslEngine = sslService.createSSLEngine(sslSettings, Settings.EMPTY);
|
||||
}
|
||||
|
||||
sslEngine.setUseClientMode(true);
|
||||
ctx.pipeline().replace(this, "ssl", new SslHandler(sslEngine));
|
||||
super.connect(ctx, remoteAddress, localAddress, promise);
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "need to use getHostName to resolve DNS name for SSL connections and hostname verification")
|
||||
private String getHostname(InetSocketAddress inetSocketAddress) {
|
||||
String hostname;
|
||||
if (HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.get(settings)) {
|
||||
hostname = inetSocketAddress.getHostName();
|
||||
} else {
|
||||
hostname = inetSocketAddress.getHostString();
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("resolved hostname [{}] for address [{}] to be used in ssl hostname verification", hostname,
|
||||
inetSocketAddress);
|
||||
}
|
||||
return hostname;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean profileSSL(Settings profileSettings, boolean defaultSSL) {
|
||||
if (PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else if (DEPRECATED_PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return DEPRECATED_PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else {
|
||||
return defaultSSL;
|
||||
}
|
||||
}
|
||||
|
||||
static SSLClientAuth profileClientAuth(Settings settings, SSLClientAuth clientAuth) {
|
||||
if (PROFILE_CLIENT_AUTH_SETTING.exists(settings)) {
|
||||
return PROFILE_CLIENT_AUTH_SETTING.get(settings);
|
||||
}
|
||||
return clientAuth;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.elasticsearch.xpack.security.authc.activedirectory.ActiveDirectoryRea
|
|||
import org.elasticsearch.xpack.security.authc.ldap.LdapRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
|
@ -32,7 +31,6 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
|
|||
import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
|
||||
/**
|
||||
* This test assumes all subclass tests will be of type SUITE. It picks a random realm configuration for the tests, and
|
||||
* writes a group to role mapping file for each node.
|
||||
|
@ -165,11 +163,11 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
|
|||
|
||||
private Settings sslSettingsForStore(Path store, String password) {
|
||||
return Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", store)
|
||||
.put("xpack.security.ssl.keystore.password", password)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.truststore.path", store)
|
||||
.put("xpack.security.ssl.truststore.password", password).build();
|
||||
.put("xpack.ssl.keystore.path", store)
|
||||
.put("xpack.ssl.keystore.password", password)
|
||||
.put("xpack.ssl.verification_mode", "certificate")
|
||||
.put("xpack.ssl.truststore.path", store)
|
||||
.put("xpack.ssl.truststore.password", password).build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.InternalClient;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
|
@ -23,7 +24,6 @@ import org.elasticsearch.xpack.security.client.SecurityClient;
|
|||
import org.elasticsearch.test.ESIntegTestCase.SuppressLocalMode;
|
||||
import org.elasticsearch.xpack.XPackClient;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -377,7 +377,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
|||
final List<NodeInfo> nodes = nodeInfos.getNodes();
|
||||
assertTrue("there is at least one node", nodes.size() > 0);
|
||||
NodeInfo ni = randomFrom(nodes);
|
||||
boolean useSSL = SecurityNetty3HttpServerTransport.SSL_SETTING.get(ni.getSettings());
|
||||
boolean useSSL = XPackSettings.HTTP_SSL_ENABLED.get(ni.getSettings());
|
||||
TransportAddress publishAddress = ni.getHttp().address().publishAddress();
|
||||
assertEquals(1, publishAddress.uniqueAddressTypeId());
|
||||
InetSocketAddress address = ((InetSocketTransportAddress) publishAddress).address();
|
||||
|
|
|
@ -25,8 +25,6 @@ import org.elasticsearch.xpack.security.authc.support.Hasher;
|
|||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
||||
|
@ -36,11 +34,9 @@ import java.nio.file.Path;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean;
|
||||
import static org.elasticsearch.test.ESTestCase.randomFrom;
|
||||
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile;
|
||||
|
||||
|
@ -87,7 +83,6 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
private final byte[] systemKey;
|
||||
private final boolean sslTransportEnabled;
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
private final boolean hostnameVerificationResolveNameEnabled;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration.
|
||||
|
@ -117,7 +112,6 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
this.subfolderPrefix = scope.name();
|
||||
this.sslTransportEnabled = sslTransportEnabled;
|
||||
this.hostnameVerificationEnabled = randomBoolean();
|
||||
this.hostnameVerificationResolveNameEnabled = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -218,29 +212,29 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
public Settings getNodeSSLSettings() {
|
||||
if (randomBoolean()) {
|
||||
return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode",
|
||||
Collections.singletonList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"),
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt",
|
||||
Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.crt",
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt",
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt",
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/openldap.crt",
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"),
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false);
|
||||
sslTransportEnabled, hostnameVerificationEnabled, false);
|
||||
}
|
||||
return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false);
|
||||
sslTransportEnabled, hostnameVerificationEnabled, false);
|
||||
}
|
||||
|
||||
public Settings getClientSSLSettings() {
|
||||
if (randomBoolean()) {
|
||||
return getSSLSettingsForPEMFiles("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem", "testclient",
|
||||
Collections.singletonList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"),
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt",
|
||||
Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt",
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"),
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true);
|
||||
sslTransportEnabled, hostnameVerificationEnabled, true);
|
||||
}
|
||||
|
||||
return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true);
|
||||
sslTransportEnabled, hostnameVerificationEnabled, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,67 +245,57 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
* @return the configuration settings
|
||||
*/
|
||||
public static Settings getSSLSettingsForStore(String resourcePathToStore, String password) {
|
||||
return getSSLSettingsForStore(resourcePathToStore, password, true, true, true, true);
|
||||
return getSSLSettingsForStore(resourcePathToStore, password, true, true, true);
|
||||
}
|
||||
|
||||
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled,
|
||||
boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled,
|
||||
boolean transportClient) {
|
||||
boolean hostnameVerificationEnabled, boolean transportClient) {
|
||||
Path store = resolveResourcePath(resourcePathToStore);
|
||||
|
||||
final String sslEnabledSetting =
|
||||
randomFrom(SecurityNetty3Transport.SSL_SETTING.getKey(), SecurityNetty3Transport.DEPRECATED_SSL_SETTING.getKey());
|
||||
Settings.Builder builder = Settings.builder().put(sslEnabledSetting, sslTransportEnabled);
|
||||
Settings.Builder builder = Settings.builder().put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled);
|
||||
|
||||
if (transportClient == false) {
|
||||
builder.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false);
|
||||
builder.put("xpack.security.http.ssl.enabled", false);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled) {
|
||||
builder.put("xpack.security.ssl.keystore.path", store)
|
||||
.put("xpack.security.ssl.keystore.password", password)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), hostnameVerificationEnabled)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(),
|
||||
hostnameVerificationResolveNameEnabled);
|
||||
builder.put("xpack.ssl.keystore.path", store)
|
||||
.put("xpack.ssl.keystore.password", password)
|
||||
.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
}
|
||||
|
||||
if (sslTransportEnabled && randomBoolean()) {
|
||||
builder.put("xpack.security.ssl.truststore.path", store)
|
||||
.put("xpack.security.ssl.truststore.password", password);
|
||||
builder.put("xpack.ssl.truststore.path", store)
|
||||
.put("xpack.ssl.truststore.password", password);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, List<String> certificateFiles,
|
||||
private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, String certificatePath,
|
||||
List<String> trustedCertificates, boolean sslTransportEnabled,
|
||||
boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled,
|
||||
boolean transportClient) {
|
||||
boolean hostnameVerificationEnabled, boolean transportClient) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
final String sslEnabledSetting =
|
||||
randomFrom(SecurityNetty3Transport.SSL_SETTING.getKey(), SecurityNetty3Transport.DEPRECATED_SSL_SETTING.getKey());
|
||||
builder.put(sslEnabledSetting, sslTransportEnabled);
|
||||
builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled);
|
||||
|
||||
if (transportClient == false) {
|
||||
builder.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false);
|
||||
builder.put("xpack.security.http.ssl.enabled", false);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled) {
|
||||
builder.put("xpack.security.ssl.key.path", resolveResourcePath(keyPath))
|
||||
.put("xpack.security.ssl.key.password", password)
|
||||
.put("xpack.security.ssl.cert", Strings.arrayToCommaDelimitedString(resolvePathsToString(certificateFiles)))
|
||||
.put(randomFrom(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(),
|
||||
SecurityNetty3Transport.DEPRECATED_HOSTNAME_VERIFICATION_SETTING.getKey()), hostnameVerificationEnabled)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(),
|
||||
hostnameVerificationResolveNameEnabled);
|
||||
builder.put("xpack.ssl.key", resolveResourcePath(keyPath))
|
||||
.put("xpack.ssl.key_passphrase", password)
|
||||
.put("xpack.ssl.certificate", resolveResourcePath(certificatePath))
|
||||
.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
|
||||
if (trustedCertificates.isEmpty() == false) {
|
||||
builder.put("xpack.security.ssl.ca", Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates)));
|
||||
builder.put("xpack.ssl.certificate_authorities",
|
||||
Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates)));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static String[] resolvePathsToString(List<String> resourcePaths) {
|
||||
private static String[] resolvePathsToString(List<String> resourcePaths) {
|
||||
List<String> resolvedPaths = new ArrayList<>(resourcePaths.size());
|
||||
for (String resource : resourcePaths) {
|
||||
resolvedPaths.add(resolveResourcePath(resource).toString());
|
||||
|
@ -319,7 +303,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
return resolvedPaths.toArray(new String[resolvedPaths.size()]);
|
||||
}
|
||||
|
||||
static Path resolveResourcePath(String resourcePathToStore) {
|
||||
private static Path resolveResourcePath(String resourcePathToStore) {
|
||||
try {
|
||||
Path path = PathUtils.get(SecuritySettingsSource.class.getResource(resourcePathToStore).toURI());
|
||||
if (Files.notExists(path)) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.test;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Guice;
|
||||
import org.elasticsearch.common.inject.Injector;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
|
@ -12,8 +13,11 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.settings.SettingsFilter;
|
||||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -53,26 +57,32 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.password", "truststore-testnode-only");
|
||||
configureFilteredSetting("xpack.security.authc.realms.pki1.truststore.algorithm", "SunX509");
|
||||
|
||||
configureFilteredSetting("xpack.security.ssl.keystore.path", "/path/to/keystore");
|
||||
configureFilteredSetting("xpack.security.ssl.ciphers", "_ciphers");
|
||||
configureFilteredSetting("xpack.security.ssl.supported_protocols", randomFrom("TLSv1", "TLSv1.1", "TLSv1.2"));
|
||||
configureFilteredSetting("xpack.security.ssl.keystore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("xpack.security.ssl.keystore.algorithm", "_algorithm");
|
||||
configureFilteredSetting("xpack.security.ssl.keystore.key_password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("xpack.security.ssl.truststore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("xpack.security.ssl.truststore.algorithm", "_algorithm");
|
||||
configureFilteredSetting("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString());
|
||||
configureFilteredSetting("xpack.ssl.cipher_suites",
|
||||
Strings.arrayToCommaDelimitedString(XPackSettings.DEFAULT_CIPHERS.toArray()));
|
||||
configureFilteredSetting("xpack.ssl.supported_protocols", randomFrom("TLSv1", "TLSv1.1", "TLSv1.2"));
|
||||
configureFilteredSetting("xpack.ssl.keystore.password", "testnode");
|
||||
configureFilteredSetting("xpack.ssl.keystore.algorithm", KeyManagerFactory.getDefaultAlgorithm());
|
||||
configureFilteredSetting("xpack.ssl.keystore.key_password", "testnode");
|
||||
configureFilteredSetting("xpack.ssl.truststore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("xpack.ssl.truststore.algorithm", TrustManagerFactory.getDefaultAlgorithm());
|
||||
|
||||
// client profile
|
||||
configureUnfilteredSetting("transport.profiles.client.port", "9500-9600");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.keystore.path", "/path/to/keystore");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ciphers", "_ciphers");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.supported_protocols",
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString());
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.cipher_suites",
|
||||
Strings.arrayToCommaDelimitedString(XPackSettings.DEFAULT_CIPHERS.toArray()));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.supported_protocols",
|
||||
randomFrom("TLSv1", "TLSv1.1", "TLSv1.2"));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.keystore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.keystore.algorithm", "_algorithm");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.keystore.key_password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.truststore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.truststore.algorithm", "_algorithm");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.password", "testnode");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.algorithm",
|
||||
KeyManagerFactory.getDefaultAlgorithm());
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.keystore.key_password", "testnode");
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.truststore.password", randomAsciiOfLength(5));
|
||||
configureFilteredSetting("transport.profiles.client.xpack.security.ssl.truststore.algorithm",
|
||||
TrustManagerFactory.getDefaultAlgorithm());
|
||||
|
||||
// custom settings, potentially added by a plugin
|
||||
configureFilteredSetting("foo.bar", "_secret");
|
||||
|
|
|
@ -22,8 +22,6 @@ import org.elasticsearch.xpack.security.authc.Realms;
|
|||
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
|
||||
import org.junit.After;
|
||||
|
@ -111,9 +109,9 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
settings.put("xpack.security.enabled", enabled);
|
||||
|
||||
final boolean httpSSLEnabled = randomBoolean();
|
||||
settings.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), httpSSLEnabled);
|
||||
settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled);
|
||||
final boolean transportSSLEnabled = randomBoolean();
|
||||
settings.put(SecurityNetty3Transport.SSL_SETTING.getKey(), transportSSLEnabled);
|
||||
settings.put("xpack.security.transport.ssl.enabled", transportSSLEnabled);
|
||||
final boolean auditingEnabled = randomBoolean();
|
||||
final String[] auditOutputs = randomFrom(new String[] {"logfile"}, new String[] {"index"}, new String[] {"logfile", "index"});
|
||||
when(auditTrail.usageStats())
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
|
|||
import org.elasticsearch.xpack.security.authc.Realm;
|
||||
import org.elasticsearch.xpack.security.authc.Realms;
|
||||
import org.elasticsearch.xpack.security.authc.file.FileRealm;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -61,7 +62,7 @@ public class SecurityTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(testSettings)
|
||||
.put("path.home", createTempDir()).build();
|
||||
Environment env = new Environment(settings);
|
||||
Security security = new Security(settings, env, new XPackLicenseState());
|
||||
Security security = new Security(settings, env, new XPackLicenseState(), new SSLService(settings, env));
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ClusterService clusterService = mock(ClusterService.class);
|
||||
settings = Security.additionalSettings(settings, false);
|
||||
|
|
|
@ -173,7 +173,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
builder.put("xpack.security.audit.index.client." + SecurityNetty3Transport.SSL_SETTING.getKey(), false);
|
||||
builder.put("xpack.security.audit.index.client.xpack.ssl.client_authentication", "none");
|
||||
}
|
||||
remoteSettings = builder.build();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.elasticsearch.xpack.security.Security;
|
|||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.XPackTransportClient;
|
||||
|
@ -229,7 +228,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(extraSettings)
|
||||
.put("cluster.name", clusterName)
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), false)
|
||||
.put("xpack.security.transport.ssl.enabled", false)
|
||||
.build();
|
||||
|
||||
return new XPackTransportClient(settings)
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
@ -37,8 +37,8 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase {
|
|||
*/
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
// fake a realm so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore);
|
||||
|
|
|
@ -24,7 +24,7 @@ import static org.hamcrest.Matchers.is;
|
|||
@Network
|
||||
public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
|
||||
|
||||
public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
private static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
|
||||
public void testResolveSubTree() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
|
|||
Settings s = Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), useSSL)
|
||||
.put("xpack.security.http.ssl.enabled", useSSL)
|
||||
.build();
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -34,8 +34,8 @@ public abstract class GroupsResolverTestCase extends ESTestCase {
|
|||
boolean useGlobalSSL = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
// fake a realm so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.keystore.path", keystore);
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
|
|||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.support.NoOpLogger;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.Before;
|
||||
|
@ -59,8 +59,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
*/
|
||||
globalSettings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit")
|
||||
.build();
|
||||
sslService = new SSLService(globalSettings, env);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
|
|||
import org.elasticsearch.xpack.security.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
@ -46,8 +46,8 @@ public class OpenLdapTests extends ESTestCase {
|
|||
useGlobalSSL = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
// fake a realm so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore);
|
||||
|
|
|
@ -10,7 +10,7 @@ import com.unboundid.ldap.sdk.LDAPConnection;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
|
@ -21,8 +21,7 @@ import org.elasticsearch.common.transport.TransportAddress;
|
|||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.file.FileRealm;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
|
@ -57,8 +56,8 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase {
|
|||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), sslClientAuth)
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", sslClientAuth)
|
||||
.put("xpack.security.authc.realms.file.type", FileRealm.TYPE)
|
||||
.put("xpack.security.authc.realms.file.order", "0")
|
||||
.put("xpack.security.authc.realms.pki1.type", PkiRealm.TYPE)
|
||||
|
@ -141,10 +140,10 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase {
|
|||
|
||||
private TransportClient createTransportClient(Settings additionalSettings) {
|
||||
Settings clientSettings = transportClientSettings();
|
||||
if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) {
|
||||
if (additionalSettings.getByPrefix("xpack.ssl.").isEmpty() == false) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ import org.elasticsearch.xpack.XPackTransportClient;
|
|||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
@ -56,8 +54,8 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
|||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), SSLClientAuth.OPTIONAL)
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.OPTIONAL)
|
||||
.put("xpack.security.authc.realms.file.type", "file")
|
||||
.put("xpack.security.authc.realms.file.order", "0")
|
||||
.put("xpack.security.authc.realms.pki1.type", "pki")
|
||||
|
@ -68,7 +66,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
|||
.put("xpack.security.authc.realms.pki1.files.role_mapping", getDataPath("role_mapping.yml"))
|
||||
.put("transport.profiles.want_client_auth.port", randomClientPortRange)
|
||||
.put("transport.profiles.want_client_auth.bind_host", "localhost")
|
||||
.put("transport.profiles.want_client_auth.xpack.security.ssl.client.auth", SSLClientAuth.OPTIONAL)
|
||||
.put("transport.profiles.want_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.OPTIONAL)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -106,7 +104,7 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
|||
.put(sslSettingsForStore)
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.build();
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ package org.elasticsearch.xpack.security.authc.pki;
|
|||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
|
@ -35,16 +38,25 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class PkiRealmTests extends ESTestCase {
|
||||
|
||||
private Settings globalSettings;
|
||||
private SSLService sslService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
globalSettings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.build();
|
||||
sslService = new SSLService(globalSettings, new Environment(globalSettings));
|
||||
}
|
||||
|
||||
public void testTokenSupport() {
|
||||
RealmConfig config = new RealmConfig("", Settings.EMPTY, globalSettings);
|
||||
PkiRealm realm = new PkiRealm(config, mock(DnRoleMapper.class));
|
||||
PkiRealm realm = new PkiRealm(config, mock(DnRoleMapper.class), sslService);
|
||||
|
||||
assertThat(realm.supports(null), is(false));
|
||||
assertThat(realm.supports(new UsernamePasswordToken("", new SecuredString(new char[0]))), is(false));
|
||||
|
@ -55,7 +67,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"));
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate });
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class));
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class), sslService);
|
||||
|
||||
X509AuthenticationToken token = realm.token(threadContext);
|
||||
assertThat(token, is(notNullValue()));
|
||||
|
@ -68,7 +80,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
X509AuthenticationToken token = new X509AuthenticationToken(new X509Certificate[] { certificate }, "Elasticsearch Test Node",
|
||||
"CN=Elasticsearch Test Node,");
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), roleMapper);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), roleMapper, sslService);
|
||||
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
|
||||
|
||||
User user = realm.authenticate(token);
|
||||
|
@ -82,7 +94,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"));
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings),
|
||||
roleMapper);
|
||||
roleMapper, sslService);
|
||||
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate });
|
||||
|
@ -102,7 +114,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
.put("truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("truststore.password", "testnode")
|
||||
.build();
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper, sslService);
|
||||
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
|
||||
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
|
@ -124,7 +136,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks"))
|
||||
.put("truststore.password", "testnode-client-profile")
|
||||
.build();
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper, sslService);
|
||||
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
|
||||
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
|
@ -141,10 +153,10 @@ public class PkiRealmTests extends ESTestCase {
|
|||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.jks"))
|
||||
.build();
|
||||
try {
|
||||
new PkiRealm(new RealmConfig("", settings, globalSettings), mock(DnRoleMapper.class));
|
||||
new PkiRealm(new RealmConfig("mypki", settings, globalSettings), mock(DnRoleMapper.class), sslService);
|
||||
fail("exception should have been thrown");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("no truststore password configured"));
|
||||
assertThat(e.getMessage(), containsString("[xpack.security.authc.realms.mypki.truststore.password] is not configured"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,6 +196,41 @@ public class PkiRealmTests extends ESTestCase {
|
|||
assertThat(token.dn(), is("EMAILADDRESS=pki@elastic.co, CN=PKI Client, OU=Security"));
|
||||
}
|
||||
|
||||
public void testNoClientAuthThrowsException() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(globalSettings)
|
||||
.put("xpack.ssl.client_authentication", "none")
|
||||
.build();
|
||||
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class),
|
||||
new SSLService(settings, new Environment(settings))));
|
||||
assertThat(e.getMessage(), containsString("has SSL with client authentication enabled"));
|
||||
}
|
||||
|
||||
public void testHttpClientAuthOnly() {
|
||||
Settings settings = Settings.builder()
|
||||
.put(globalSettings)
|
||||
.put("xpack.ssl.client_authentication", "none")
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", randomFrom(SSLClientAuth.OPTIONAL, SSLClientAuth.REQUIRED))
|
||||
.build();
|
||||
new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class),
|
||||
new SSLService(settings, new Environment(settings)));
|
||||
}
|
||||
|
||||
public void testNoSSLThrowsException() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(globalSettings)
|
||||
.put("xpack.security.transport.ssl.enabled", false)
|
||||
.build();
|
||||
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> new PkiRealm(new RealmConfig("", Settings.EMPTY, settings), mock(DnRoleMapper.class),
|
||||
new SSLService(settings, new Environment(settings))));
|
||||
assertThat(e.getMessage(), containsString("has SSL with client authentication enabled"));
|
||||
}
|
||||
|
||||
static X509Certificate readCert(Path path) throws Exception {
|
||||
try (InputStream in = Files.newInputStream(path)) {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.authc.pki;
|
||||
|
||||
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@ClusterScope(numClientNodes = 0, supportsDedicatedMasters = false, numDataNodes = 1)
|
||||
public class PkiWithoutClientAuthenticationTests extends SecurityIntegTestCase {
|
||||
private TrustManager[] trustAllCerts = new TrustManager[] {
|
||||
new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), false)
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(),
|
||||
randomFrom(SSLClientAuth.NO.name(), false, "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT)))
|
||||
.put("xpack.security.authc.realms.pki1.type", "pki")
|
||||
.put("xpack.security.authc.realms.pki1.order", "0")
|
||||
.build();
|
||||
}
|
||||
|
||||
public void testThatTransportClientWorks() {
|
||||
Client client = internalCluster().transportClient();
|
||||
assertGreenClusterState(client);
|
||||
}
|
||||
|
||||
public void testThatHttpWorks() throws Exception {
|
||||
SSLContext sc = SSLContext.getInstance("SSL");
|
||||
sc.init(null, trustAllCerts, new SecureRandom());
|
||||
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sc);
|
||||
try (RestClient restClient = createRestClient(httpClientBuilder -> httpClientBuilder.setSSLStrategy(sessionStrategy), "https")) {
|
||||
Response response = restClient.performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.authc.pki;
|
||||
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@ClusterScope(numClientNodes = 0, supportsDedicatedMasters = false, numDataNodes = 1)
|
||||
public class PkiWithoutSSLTests extends SecurityIntegTestCase {
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.put("xpack.security.authc.realms.pki1.type", "pki")
|
||||
.put("xpack.security.authc.realms.pki1.order", "0")
|
||||
.build();
|
||||
}
|
||||
|
||||
public void testThatTransportClientWorks() {
|
||||
Client client = internalCluster().transportClient();
|
||||
assertGreenClusterState(client);
|
||||
}
|
||||
|
||||
public void testThatHttpWorks() throws Exception {
|
||||
Response response = getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
|||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
|
||||
|
@ -46,7 +47,7 @@ public class SecurityRestFilterTests extends ESTestCase {
|
|||
when(licenseState.isAuthAllowed()).thenReturn(true);
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY));
|
||||
filter = new SecurityRestFilter(authcService, restController, Settings.EMPTY, threadPool, licenseState);
|
||||
filter = new SecurityRestFilter(authcService, restController, Settings.EMPTY, threadPool, licenseState, mock(SSLService.class));
|
||||
verify(restController).registerFilter(filter);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import org.elasticsearch.transport.Transport;
|
|||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.file.FileRealm;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -64,7 +64,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
if (sslTransportEnabled()) {
|
||||
settingsBuilder.put("transport.profiles.client.xpack.security.truststore.path", store) // settings for client truststore
|
||||
.put("transport.profiles.client.xpack.security.truststore.password", "testnode")
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true);
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED);
|
||||
}
|
||||
|
||||
return settingsBuilder
|
||||
|
@ -97,7 +97,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
.put("network.host", "localhost")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put("discovery.zen.ping.unicast.hosts", unicastHost)
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), sslTransportEnabled())
|
||||
.put("xpack.security.transport.ssl.enabled", sslTransportEnabled())
|
||||
.put("xpack.security.audit.enabled", false)
|
||||
.put("path.home", home)
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
|
||||
|
@ -133,7 +133,7 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
.put(Security.USER_SETTING.getKey(), "test_user:changeme")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put("discovery.zen.ping.unicast.hosts", "localhost:" + randomClientPort)
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), sslTransportEnabled())
|
||||
.put("xpack.security.transport.ssl.enabled", sslTransportEnabled())
|
||||
.put("xpack.security.audit.enabled", false)
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
|
||||
.put("discovery.initial_state_timeout", "2s")
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.elasticsearch.transport.TransportResponseHandler;
|
|||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -287,7 +288,8 @@ public class TransportFilterTests extends ESIntegTestCase {
|
|||
public InternalPluginServerTransportService(Settings settings, Transport transport, ThreadPool threadPool,
|
||||
AuthenticationService authcService, AuthorizationService authzService,
|
||||
SecurityActionMapper actionMapper) {
|
||||
super(settings, transport, threadPool, authcService, authzService, actionMapper, mock(XPackLicenseState.class));
|
||||
super(settings, transport, threadPool, authcService, authzService, actionMapper, mock(XPackLicenseState.class),
|
||||
mock(SSLService.class));
|
||||
when(licenseState.isAuthAllowed()).thenReturn(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.client.Client;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
@ -16,6 +17,7 @@ import java.util.Map.Entry;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
// TODO delete this test?
|
||||
public class IPHostnameVerificationTests extends SecurityIntegTestCase {
|
||||
Path keystore;
|
||||
|
||||
|
@ -29,7 +31,7 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -54,15 +56,14 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-ip-only")
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-ip-only")
|
||||
return settingsBuilder.put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.ssl.keystore.password", "testnode-ip-only")
|
||||
.put("xpack.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.ssl.truststore.password", "testnode-ip-only")
|
||||
.put(TransportSettings.BIND_HOST.getKey(), "127.0.0.1")
|
||||
.put("network.host", "127.0.0.1")
|
||||
.put("xpack.security.ssl.client.auth", "false")
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), false)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.NONE)
|
||||
.put("xpack.ssl.verification_mode", "full")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -71,19 +72,18 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Settings clientSettings = super.transportClientSettings();
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
clientSettings = builder.build();
|
||||
|
||||
return Settings.builder().put(clientSettings)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-ip-only")
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-ip-only")
|
||||
.put("xpack.ssl.verification_mode", "certificate")
|
||||
.put("xpack.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.ssl.keystore.password", "testnode-ip-only")
|
||||
.put("xpack.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.ssl.truststore.password", "testnode-ip-only")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.elasticsearch.common.logging.Loggers;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
|
@ -69,9 +69,9 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase {
|
|||
iterations = randomIntBetween(10, 100);
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path",
|
||||
.put("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
sslService = new SSLService(settings, env);
|
||||
|
@ -100,7 +100,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase {
|
|||
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
engine.setUseClientMode(true);
|
||||
return Channels.pipeline(
|
||||
new SslHandler(engine));
|
||||
|
@ -137,7 +137,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase {
|
|||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
engine.setUseClientMode(true);
|
||||
return Channels.pipeline(
|
||||
new SslHandler(engine),
|
||||
|
@ -208,7 +208,7 @@ public class Netty3HandshakeWaitingHandlerTests extends ESTestCase {
|
|||
return new ChannelPipelineFactory() {
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
sslEngine.setUseClientMode(false);
|
||||
return Channels.pipeline(new SslHandler(sslEngine),
|
||||
new SimpleChannelHandler() {
|
||||
|
|
|
@ -11,8 +11,8 @@ import org.elasticsearch.common.util.BigArrays;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.http.HttpTransportSettings;
|
||||
import org.elasticsearch.http.netty3.Netty3HttpMockUtil;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
@ -40,8 +40,8 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
public void createSSLService() throws Exception {
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -49,7 +49,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -61,8 +64,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -72,10 +77,11 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.REQUIRED).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -85,10 +91,11 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), SSLClientAuth.NO.name().toLowerCase(Locale.ROOT), "false", "FALSE");
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.NONE).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -99,7 +106,9 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testCustomSSLConfiguration() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -108,7 +117,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.supported_protocols", "TLSv1.2")
|
||||
.build();
|
||||
sslService = new SSLService(settings, new Environment(settings));
|
||||
|
@ -123,7 +132,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testDisablesCompressionByDefaultForSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
|
@ -132,7 +141,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testLeavesCompressionOnIfNotSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), false).build();
|
||||
.put("xpack.security.http.ssl.enabled", false).build();
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
assertThat(pluginSettingsBuilder.build().isEmpty(), is(true));
|
||||
|
@ -140,7 +149,7 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testDoesNotChangeExplicitlySetCompression() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true)
|
||||
.build();
|
||||
|
||||
|
@ -151,10 +160,10 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -167,9 +176,9 @@ public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
|
|
@ -11,8 +11,9 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty3.Netty3MockUtil;
|
||||
|
@ -20,6 +21,7 @@ import org.jboss.netty.channel.ChannelPipelineFactory;
|
|||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -38,37 +40,38 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
public void createSSLService() throws Exception {
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeDisabledByProfile() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl", false).build());
|
||||
Settings.builder().put("xpack.security.ssl.enabled", false).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class), nullValue());
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeEnabledByProfile() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), false).build();
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", false).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl", true).build());
|
||||
Settings.builder().put("xpack.security.ssl.enabled", true).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());
|
||||
}
|
||||
|
||||
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
|
@ -78,7 +81,7 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
|
@ -89,10 +92,13 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true");
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
|
@ -103,10 +109,12 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
|
@ -119,8 +127,10 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
|
@ -131,50 +141,65 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testProfileRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING, value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder().put(SecurityNetty3Transport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -189,10 +214,10 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
|
||||
public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), false)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -202,4 +227,36 @@ public class SecurityNetty3TransportTests extends ESTestCase {
|
|||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
assertNotNull(transport.configureServerChannelPipelineFactory(randomAsciiOfLength(6), Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testTransportSSLOverridesGlobalSSL() throws Exception {
|
||||
final boolean useGlobalKeystoreWithoutKey = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.transport.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.transport.ssl.client_authentication", "none")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir());
|
||||
if (useGlobalKeystoreWithoutKey) {
|
||||
builder.put("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.ssl.keystore.password", "truststore-testnode-only");
|
||||
}
|
||||
Settings settings = builder.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("default", Settings.EMPTY);
|
||||
final SSLEngine engine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
assertFalse(engine.getNeedClientAuth());
|
||||
assertFalse(engine.getWantClientAuth());
|
||||
|
||||
// get the global and verify that it is different in that it requires client auth
|
||||
final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertTrue(globalEngine.getNeedClientAuth());
|
||||
assertFalse(globalEngine.getWantClientAuth());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder settingsBuilder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
settingsBuilder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -54,12 +54,12 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname")
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname")
|
||||
// disable hostname verification as this test uses non-localhost addresses
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
return settingsBuilder.put("xpack.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.ssl.keystore.password", "testnode-no-subjaltname")
|
||||
.put("xpack.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.ssl.truststore.password", "testnode-no-subjaltname")
|
||||
// disable hostname verification as this test uses certs without a valid SAN or DNS in the CN
|
||||
.put("xpack.ssl.verification_mode", "certificate")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -72,19 +72,19 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.startsWith(Security.setting("ssl.")) == false) {
|
||||
if (key.startsWith("xpack.ssl.") == false) {
|
||||
builder.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
builder.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client keystore
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname");
|
||||
builder.put("xpack.ssl.verification_mode", "certificate")
|
||||
.put("xpack.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client keystore
|
||||
.put("xpack.ssl.keystore.password", "testnode-no-subjaltname");
|
||||
|
||||
if (randomBoolean()) {
|
||||
// randomly set the truststore, if not set the keystore should be used
|
||||
builder.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname");
|
||||
builder.put("xpack.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.ssl.truststore.password", "testnode-no-subjaltname");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public class SslHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
InetSocketAddress inetSocketAddress = ((InetSocketTransportAddress) transportAddress).address();
|
||||
|
||||
Settings settings = Settings.builder().put(transportClientSettings())
|
||||
.put(SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.verification_mode", "full")
|
||||
.build();
|
||||
|
||||
try (TransportClient client = new XPackTransportClient(settings)) {
|
||||
|
|
|
@ -16,8 +16,9 @@ import org.elasticsearch.http.HttpTransportSettings;
|
|||
import org.elasticsearch.http.netty4.Netty4HttpMockUtil;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -42,8 +43,8 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
public void createSSLService() throws Exception {
|
||||
Path testNodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testNodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testNodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -51,7 +52,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder().put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -64,8 +68,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put("xpack.security.http.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -76,10 +82,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put("xpack.security.http.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -90,10 +98,12 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), SSLClientAuth.NO.name().toLowerCase(Locale.ROOT), "false", "FALSE");
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
.put(env.settings())
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put("xpack.security.http.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -105,7 +115,9 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testCustomSSLConfiguration() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
.put(env.settings())
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
|
@ -115,7 +127,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put("xpack.security.http.ssl.supported_protocols", "TLSv1.2")
|
||||
.build();
|
||||
sslService = new SSLService(settings, new Environment(settings));
|
||||
|
@ -131,7 +143,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testDisablesCompressionByDefaultForSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build();
|
||||
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
|
@ -140,7 +152,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testLeavesCompressionOnIfNotSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), false).build();
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), false).build();
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
assertThat(pluginSettingsBuilder.build().isEmpty(), is(true));
|
||||
|
@ -148,7 +160,7 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testDoesNotChangeExplicitlySetCompression() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true)
|
||||
.build();
|
||||
|
||||
|
@ -159,10 +171,10 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -175,9 +187,9 @@ public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
|
|||
|
||||
public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
|
|
@ -17,10 +17,12 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
|||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty4.Netty4MockUtil;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -39,8 +41,8 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
public void createSSLService() throws Exception {
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -54,7 +56,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
private SecurityNetty4Transport createTransport(boolean sslEnabled, Settings additionalSettings) {
|
||||
final Settings settings =
|
||||
Settings.builder()
|
||||
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), sslEnabled)
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslEnabled)
|
||||
.put(additionalSettings)
|
||||
.build();
|
||||
return new SecurityNetty4Transport(
|
||||
|
@ -72,7 +74,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
SecurityNetty4Transport transport = createTransport(true);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl", false).build());
|
||||
Settings.builder().put("xpack.security.ssl.enabled", false).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class), nullValue());
|
||||
}
|
||||
|
@ -81,7 +83,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
SecurityNetty4Transport transport = createTransport(false);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl", true).build());
|
||||
Settings.builder().put("xpack.security.ssl.enabled", true).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class), notNullValue());
|
||||
}
|
||||
|
@ -104,9 +106,13 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true");
|
||||
SecurityNetty4Transport transport =
|
||||
createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -115,9 +121,13 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
|
||||
SecurityNetty4Transport transport =
|
||||
createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -127,8 +137,12 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
|
||||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
SecurityNetty4Transport transport =
|
||||
createTransport(true, Settings.builder().put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -137,22 +151,34 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testProfileRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING, value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
|
||||
|
@ -160,10 +186,16 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
|
||||
public void testProfileOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
final ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
|
||||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
|
||||
|
@ -171,10 +203,10 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -188,10 +220,10 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
|
||||
public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), false)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
|
@ -200,4 +232,35 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService);
|
||||
assertNotNull(transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testTransportSSLOverridesGlobalSSL() throws Exception {
|
||||
final boolean useGlobalKeystoreWithoutKey = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.transport.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.transport.ssl.client_authentication", "none")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir());
|
||||
if (useGlobalKeystoreWithoutKey) {
|
||||
builder.put("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.ssl.keystore.password", "truststore-testnode-only");
|
||||
}
|
||||
Settings settings = builder.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
final ChannelHandler handler = transport.getServerChannelInitializer("default", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
final SSLEngine engine = ch.pipeline().get(SslHandler.class).engine();
|
||||
assertFalse(engine.getNeedClientAuth());
|
||||
assertFalse(engine.getWantClientAuth());
|
||||
|
||||
// get the global and verify that it is different in that it requires client auth
|
||||
final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertTrue(globalEngine.getNeedClientAuth());
|
||||
assertFalse(globalEngine.getWantClientAuth());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackTransportClient;
|
||||
|
@ -48,7 +47,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
|
|||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +61,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
|
|||
.put(transportClientSettings())
|
||||
.put("node.name", "programmatic_transport_client")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.putArray("xpack.security.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"})
|
||||
.putArray("xpack.ssl.cipher_suites", "TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA")
|
||||
.build())) {
|
||||
|
||||
TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
|
||||
|
@ -81,7 +80,7 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
|
|||
.put(transportClientSettings())
|
||||
.put("node.name", "programmatic_transport_client")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.putArray("xpack.security.ssl.supported_protocols", new String[]{"SSLv3"})
|
||||
.putArray("xpack.ssl.supported_protocols", new String[]{"SSLv3"})
|
||||
.build())) {
|
||||
|
||||
TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackTransportClient;
|
||||
|
@ -70,15 +70,14 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
.put("transport.profiles.client.port", randomClientPortRange)
|
||||
// make sure this is "localhost", no matter if ipv4 or ipv6, but be consistent
|
||||
.put("transport.profiles.client.bind_host", "localhost")
|
||||
.put("transport.profiles.client.xpack.security.truststore.path", store.toAbsolutePath()) // settings for client truststore
|
||||
.put("transport.profiles.client.xpack.security.truststore.password", "testnode-client-profile")
|
||||
.put("transport.profiles.client.xpack.security.ssl.truststore.path", store.toAbsolutePath())
|
||||
.put("transport.profiles.client.xpack.security.ssl.truststore.password", "testnode-client-profile")
|
||||
.put("transport.profiles.no_ssl.port", randomNonSslPortRange)
|
||||
.put("transport.profiles.no_ssl.bind_host", "localhost")
|
||||
.put(randomFrom(
|
||||
"transport.profiles.no_ssl.xpack.security.ssl.enabled", "transport.profiles.no_ssl.xpack.security.ssl"), "false")
|
||||
.put("transport.profiles.no_ssl.xpack.security.ssl.enabled", "false")
|
||||
.put("transport.profiles.no_client_auth.port", randomNoClientAuthPortRange)
|
||||
.put("transport.profiles.no_client_auth.bind_host", "localhost")
|
||||
.put("transport.profiles.no_client_auth.xpack.security.ssl.client.auth", false)
|
||||
.put("transport.profiles.no_client_auth.xpack.security.ssl.client_authentication", SSLClientAuth.NONE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -89,10 +88,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
|
||||
private TransportClient createTransportClient(Settings additionalSettings) {
|
||||
Settings clientSettings = transportClientSettings();
|
||||
if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) {
|
||||
if (additionalSettings.getByPrefix("xpack.ssl.").isEmpty() == false) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +233,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
public void testThatTransportClientCanConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), false)
|
||||
.put("xpack.security.transport.ssl.enabled", false)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
|
@ -307,10 +306,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "truststore-testnode-only")
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(),
|
||||
|
@ -329,10 +328,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "truststore-testnode-only")
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client")));
|
||||
|
@ -353,10 +352,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "truststore-testnode-only")
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
|
||||
|
@ -376,10 +375,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.truststore.path",
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.security.ssl.truststore.password", "truststore-testnode-only")
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
|
||||
|
@ -399,7 +398,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
|
||||
|
@ -419,7 +418,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client")));
|
||||
|
@ -439,7 +438,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(),
|
||||
|
@ -451,26 +450,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with the default JDK truststore; this truststore only trusts the known good public
|
||||
* certificate authorities. This test connects to the no_ssl profile, which does not use SSL so the connection
|
||||
* will not work
|
||||
*/
|
||||
public void testThatSSLTransportClientWithNoTruststoreCannotConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.build();
|
||||
try (TransportClient transportClient = new XPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
|
||||
assertGreenClusterState(transportClient);
|
||||
fail("Expected NoNodeAvailableException");
|
||||
} catch (NoNodeAvailableException e) {
|
||||
assertThat(e.getMessage(), containsString("None of the configured nodes are available: [{#transport#-"));
|
||||
}
|
||||
}
|
||||
|
||||
private static int getProfilePort(String profile) {
|
||||
TransportAddress transportAddress =
|
||||
randomFrom(internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddresses());
|
||||
|
|
Binary file not shown.
|
@ -89,6 +89,8 @@ import org.elasticsearch.xpack.security.Security;
|
|||
import org.elasticsearch.xpack.security.SecurityFeatureSet;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.ssl.SSLConfigurationReloader;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.support.clock.Clock;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.watcher.Watcher;
|
||||
|
@ -152,6 +154,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
protected final XPackExtensionsService extensionsService;
|
||||
|
||||
protected XPackLicenseState licenseState;
|
||||
protected SSLService sslService;
|
||||
protected Licensing licensing;
|
||||
protected Security security;
|
||||
protected Monitoring monitoring;
|
||||
|
@ -163,9 +166,10 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
this.transportClientMode = transportClientMode(settings);
|
||||
this.env = transportClientMode ? null : new Environment(settings);
|
||||
this.licenseState = new XPackLicenseState();
|
||||
this.sslService = new SSLService(settings, env);
|
||||
|
||||
this.licensing = new Licensing(settings);
|
||||
this.security = new Security(settings, env, licenseState);
|
||||
this.security = new Security(settings, env, licenseState, sslService);
|
||||
this.monitoring = new Monitoring(settings, env, licenseState);
|
||||
this.watcher = new Watcher(settings);
|
||||
this.graph = new Graph(settings);
|
||||
|
@ -207,6 +211,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
ResourceWatcherService resourceWatcherService, ScriptService scriptService,
|
||||
SearchRequestParsers searchRequestParsers) {
|
||||
List<Object> components = new ArrayList<>();
|
||||
components.add(sslService);
|
||||
|
||||
final InternalClient internalClient = new InternalClient(settings, threadPool, client, security.getCryptoService());
|
||||
components.add(internalClient);
|
||||
|
||||
|
@ -217,7 +223,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
|
||||
components.addAll(security.createComponents(internalClient, threadPool, clusterService, resourceWatcherService,
|
||||
extensionsService.getExtensions()));
|
||||
components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService));
|
||||
components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService, sslService));
|
||||
|
||||
// watcher http stuff
|
||||
Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>();
|
||||
|
@ -226,12 +232,14 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories);
|
||||
HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry);
|
||||
components.add(httpTemplateParser);
|
||||
final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, env);
|
||||
final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, env, sslService);
|
||||
components.add(httpClient);
|
||||
|
||||
components.addAll(createNotificationComponents(clusterService.getClusterSettings(), httpClient,
|
||||
httpTemplateParser, scriptService));
|
||||
|
||||
// just create the reloader as it will pull all of the loaded ssl configurations and start watching them
|
||||
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService);
|
||||
return components;
|
||||
}
|
||||
|
||||
|
@ -288,7 +296,6 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
settings.addAll(MonitoringSettings.getSettings());
|
||||
settings.addAll(watcher.getSettings());
|
||||
settings.addAll(licensing.getSettings());
|
||||
|
||||
settings.addAll(XPackSettings.getAllSettings());
|
||||
|
||||
// we add the `xpack.version` setting to all internal indices
|
||||
|
|
|
@ -6,13 +6,22 @@
|
|||
package org.elasticsearch.xpack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.VerificationMode;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
/**
|
||||
* A container for xpack setting constants.
|
||||
|
@ -41,6 +50,192 @@ public class XPackSettings {
|
|||
/** Setting for enabling or disabling document/field level security. Defaults to true. */
|
||||
public static final Setting<Boolean> DLS_FLS_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".dls_fls", true);
|
||||
|
||||
/** Setting for enabling or disabling transport ssl. Defaults to false. */
|
||||
public static final Setting<Boolean> TRANSPORT_SSL_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".transport.ssl", false);
|
||||
|
||||
/** Setting for enabling or disabling http ssl. Defaults to false. */
|
||||
public static final Setting<Boolean> HTTP_SSL_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".http.ssl", false);
|
||||
|
||||
/*
|
||||
* SSL settings. These are the settings that are specifically registered for SSL. Many are private as we do not explicitly use them
|
||||
* but instead parse based on a prefix (eg *.ssl.*)
|
||||
*/
|
||||
public static final List<String> DEFAULT_CIPHERS =
|
||||
Arrays.asList("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA");
|
||||
public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1");
|
||||
public static final SSLClientAuth CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED;
|
||||
public static final SSLClientAuth HTTP_CLIENT_AUTH_DEFAULT = SSLClientAuth.NONE;
|
||||
public static final VerificationMode VERIFICATION_MODE_DEFAULT = VerificationMode.FULL;
|
||||
|
||||
// global settings that apply to everything!
|
||||
private static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting("xpack.ssl.cipher_suites", DEFAULT_CIPHERS,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING = Setting.listSetting("xpack.ssl.supported_protocols",
|
||||
DEFAULT_SUPPORTED_PROTOCOLS, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING = new Setting<>("xpack.ssl.client_authentication",
|
||||
CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<VerificationMode> VERIFICATION_MODE_SETTING = new Setting<>("xpack.ssl.verification_mode",
|
||||
VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> KEYSTORE_PATH_SETTING = new Setting<>("xpack.ssl.keystore.path",
|
||||
s -> System.getProperty("javax.net.ssl.keyStore"), Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = new Setting<>("xpack.ssl.keystore.password",
|
||||
s -> System.getProperty("javax.net.ssl.keyStorePassword"), Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>("xpack.ssl.keystore.algorithm",
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.ssl.keystore.key_password", KEYSTORE_PASSWORD_SETTING, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = new Setting<>("xpack.ssl.truststore.path",
|
||||
s -> System.getProperty("javax.net.ssl.trustStore"), Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = new Setting<>("xpack.ssl.truststore.password",
|
||||
s -> System.getProperty("javax.net.ssl.trustStorePassword"), Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("xpack.ssl.truststore.algorithm",
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> KEY_PATH_SETTING =
|
||||
new Setting<>("xpack.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> KEY_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.ssl.key_passphrase", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> CERT_SETTING =
|
||||
new Setting<>("xpack.ssl.certificate", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> CA_PATHS_SETTING = Setting.listSetting("xpack.ssl.certificate_authorities",
|
||||
Collections.emptyList(), s -> s, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// http specific settings
|
||||
private static final Setting<List<String>> HTTP_CIPHERS_SETTING = Setting.listSetting("xpack.security.http.ssl.cipher_suites",
|
||||
DEFAULT_CIPHERS, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> HTTP_SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting("xpack.security.http.ssl.supported_protocols", emptyList(), Function.identity(),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<SSLClientAuth> HTTP_CLIENT_AUTH_SETTING = new Setting<>("xpack.security.http.ssl.client_authentication",
|
||||
CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<VerificationMode> HTTP_VERIFICATION_MODE_SETTING =
|
||||
new Setting<>("xpack.security.http.ssl.verification_mode", VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_KEYSTORE_PATH_SETTING = new Setting<>("xpack.security.http.ssl.keystore.path",
|
||||
(String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_KEYSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.http.ssl.keystore.password", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> HTTP_KEYSTORE_ALGORITHM_SETTING = new Setting<>("xpack.security.http.ssl.keystore.algorithm",
|
||||
"", Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.http.ssl.keystore.key_password", HTTP_KEYSTORE_PASSWORD_SETTING, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_TRUSTSTORE_PATH_SETTING = new Setting<>("xpack.security.http.ssl.truststore.path",
|
||||
(String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_TRUSTSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.http.ssl.truststore.password", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> HTTP_TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("xpack.security.http.ssl.truststore.algorithm",
|
||||
"", Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_KEY_PATH_SETTING =
|
||||
new Setting<>("xpack.security.http.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_KEY_PASSWORD_SETTING = new Setting<>("xpack.security.http.ssl.key_passphrase",
|
||||
(String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> HTTP_CERT_SETTING = new Setting<>("xpack.security.http.ssl.certificate",
|
||||
(String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> HTTP_CA_PATHS_SETTING =
|
||||
Setting.listSetting("xpack.security.http.ssl.certificate_authorities", emptyList(), s -> s,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
|
||||
// transport specific settings
|
||||
private static final Setting<List<String>> TRANSPORT_CIPHERS_SETTING =
|
||||
Setting.listSetting("xpack.security.transport.ssl.cipher_suites", DEFAULT_CIPHERS, Function.identity(),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> TRANSPORT_SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting("xpack.security.transport.ssl.supported_protocols", emptyList(), Function.identity(),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<SSLClientAuth> TRANSPORT_CLIENT_AUTH_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.client_authentication", CLIENT_AUTH_DEFAULT.name(), SSLClientAuth::parse,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<VerificationMode> TRANSPORT_VERIFICATION_MODE_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.verification_mode", VERIFICATION_MODE_DEFAULT.name(), VerificationMode::parse,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_KEYSTORE_PATH_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.keystore.path", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_KEYSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.keystore.password", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> TRANSPORT_KEYSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.keystore.algorithm", "", Function.identity(), Property.NodeScope,
|
||||
Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.keystore.key_password", TRANSPORT_KEYSTORE_PASSWORD_SETTING, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_TRUSTSTORE_PATH_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.truststore.path", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_TRUSTSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.truststore.password", (String) null, Optional::ofNullable,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<String> TRANSPORT_TRUSTSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.truststore.algorithm", "", Function.identity(),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_KEY_PATH_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.key", (String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_KEY_PASSWORD_SETTING =
|
||||
new Setting<>("xpack.security.transport.ssl.key_passphrase", (String) null, Optional::ofNullable, Property.NodeScope,
|
||||
Property.Filtered);
|
||||
private static final Setting<Optional<String>> TRANSPORT_CERT_SETTING = new Setting<>("xpack.security.transport.ssl.certificate",
|
||||
(String) null, Optional::ofNullable, Property.NodeScope, Property.Filtered);
|
||||
private static final Setting<List<String>> TRANSPORT_CA_PATHS_SETTING =
|
||||
Setting.listSetting("xpack.security.transport.ssl.certificate_authorities", emptyList(), s -> s,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
/* End SSL settings */
|
||||
|
||||
static {
|
||||
ALL_SETTINGS.add(CIPHERS_SETTING);
|
||||
ALL_SETTINGS.add(SUPPORTED_PROTOCOLS_SETTING);
|
||||
ALL_SETTINGS.add(KEYSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(KEYSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(KEYSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(KEY_PATH_SETTING);
|
||||
ALL_SETTINGS.add(KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(CERT_SETTING);
|
||||
ALL_SETTINGS.add(TRUSTSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(TRUSTSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(TRUSTSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(CA_PATHS_SETTING);
|
||||
ALL_SETTINGS.add(VERIFICATION_MODE_SETTING);
|
||||
ALL_SETTINGS.add(CLIENT_AUTH_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_CIPHERS_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_SUPPORTED_PROTOCOLS_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEYSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEYSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEYSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEY_PATH_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_CERT_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_TRUSTSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_TRUSTSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_TRUSTSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_CA_PATHS_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_VERIFICATION_MODE_SETTING);
|
||||
ALL_SETTINGS.add(HTTP_CLIENT_AUTH_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_CIPHERS_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_SUPPORTED_PROTOCOLS_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEYSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEYSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEYSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEY_PATH_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_KEY_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_CERT_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_PATH_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_PASSWORD_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_TRUSTSTORE_ALGORITHM_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_CA_PATHS_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_VERIFICATION_MODE_SETTING);
|
||||
ALL_SETTINGS.add(TRANSPORT_CLIENT_AUTH_SETTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Setting for the enabled state of features in xpack.
|
||||
*
|
||||
|
|
|
@ -5,25 +5,20 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.common.http;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchTimeoutException;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.common.http.auth.ApplicableHttpAuth;
|
||||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -32,12 +27,8 @@ import java.net.SocketTimeoutException;
|
|||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -45,30 +36,13 @@ import java.util.Map;
|
|||
/**
|
||||
* Client class to wrap http connections
|
||||
*/
|
||||
public class HttpClient extends AbstractLifecycleComponent {
|
||||
public class HttpClient extends AbstractComponent {
|
||||
|
||||
static final String SETTINGS_SSL_PREFIX = "xpack.http.ssl.";
|
||||
static final String SETTINGS_PROXY_PREFIX = "xpack.http.proxy.";
|
||||
static final String SETTINGS_SSL_SECURITY_PREFIX = "xpack.security.ssl.";
|
||||
|
||||
public static final String SETTINGS_SSL_PROTOCOL = SETTINGS_SSL_PREFIX + "protocol";
|
||||
static final String SETTINGS_SSL_SECURITY_PROTOCOL = SETTINGS_SSL_SECURITY_PREFIX + "protocol";
|
||||
public static final String SETTINGS_SSL_KEYSTORE = SETTINGS_SSL_PREFIX + "keystore.path";
|
||||
static final String SETTINGS_SSL_SECURITY_KEYSTORE = SETTINGS_SSL_SECURITY_PREFIX + "keystore.path";
|
||||
public static final String SETTINGS_SSL_KEYSTORE_PASSWORD = SETTINGS_SSL_PREFIX + "keystore.password";
|
||||
static final String SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "keystore.password";
|
||||
public static final String SETTINGS_SSL_KEYSTORE_KEY_PASSWORD = SETTINGS_SSL_PREFIX + "keystore.key_password";
|
||||
static final String SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "keystore.key_password";
|
||||
public static final String SETTINGS_SSL_KEYSTORE_ALGORITHM = SETTINGS_SSL_PREFIX + "keystore.algorithm";
|
||||
static final String SETTINGS_SSL_SECURITY_KEYSTORE_ALGORITHM = SETTINGS_SSL_SECURITY_PREFIX + "keystore.algorithm";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE = SETTINGS_SSL_PREFIX + "truststore.path";
|
||||
static final String SETTINGS_SSL_SECURITY_TRUSTSTORE = SETTINGS_SSL_SECURITY_PREFIX + "truststore.path";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE_PASSWORD = SETTINGS_SSL_PREFIX + "truststore.password";
|
||||
static final String SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD = SETTINGS_SSL_SECURITY_PREFIX + "truststore.password";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_PREFIX + "truststore.algorithm";
|
||||
static final String SETTINGS_SSL_SECURITY_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_SECURITY_PREFIX + "truststore.algorithm";
|
||||
public static final String SETTINGS_PROXY_HOST = SETTINGS_PROXY_PREFIX + "host";
|
||||
public static final String SETTINGS_PROXY_PORT = SETTINGS_PROXY_PREFIX + "port";
|
||||
static final String SETTINGS_PROXY_HOST = SETTINGS_PROXY_PREFIX + "host";
|
||||
static final String SETTINGS_PROXY_PORT = SETTINGS_PROXY_PREFIX + "port";
|
||||
|
||||
private final HttpAuthRegistry httpAuthRegistry;
|
||||
private final Environment env;
|
||||
|
@ -78,16 +52,12 @@ public class HttpClient extends AbstractLifecycleComponent {
|
|||
private SSLSocketFactory sslSocketFactory;
|
||||
private HttpProxy proxy = HttpProxy.NO_PROXY;
|
||||
|
||||
public HttpClient(Settings settings, HttpAuthRegistry httpAuthRegistry, Environment env) {
|
||||
public HttpClient(Settings settings, HttpAuthRegistry httpAuthRegistry, Environment env, SSLService sslService) {
|
||||
super(settings);
|
||||
this.httpAuthRegistry = httpAuthRegistry;
|
||||
this.env = env;
|
||||
defaultConnectionTimeout = settings.getAsTime("xpack.http.default_connection_timeout", TimeValue.timeValueSeconds(10));
|
||||
defaultReadTimeout = settings.getAsTime("xpack.http.default_read_timeout", TimeValue.timeValueSeconds(10));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws ElasticsearchException {
|
||||
Integer proxyPort = settings.getAsInt(SETTINGS_PROXY_PORT, null);
|
||||
String proxyHost = settings.get(SETTINGS_PROXY_HOST, null);
|
||||
if (proxyPort != null && Strings.hasText(proxyHost)) {
|
||||
|
@ -99,22 +69,7 @@ public class HttpClient extends AbstractLifecycleComponent {
|
|||
SETTINGS_PROXY_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings.getByPrefix(SETTINGS_SSL_PREFIX).getAsMap().isEmpty() ||
|
||||
!settings.getByPrefix(SETTINGS_SSL_SECURITY_PREFIX).getAsMap().isEmpty()) {
|
||||
sslSocketFactory = createSSLSocketFactory(settings);
|
||||
} else {
|
||||
logger.trace("no ssl context configured");
|
||||
sslSocketFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ElasticsearchException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose() throws ElasticsearchException {
|
||||
sslSocketFactory = sslService.sslSocketFactory(settings.getByPrefix(SETTINGS_SSL_PREFIX));
|
||||
}
|
||||
|
||||
public HttpResponse execute(HttpRequest request) throws IOException {
|
||||
|
@ -153,7 +108,7 @@ public class HttpClient extends AbstractLifecycleComponent {
|
|||
HttpProxy proxyToUse = request.proxy != null ? request.proxy : proxy;
|
||||
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(proxyToUse.proxy());
|
||||
if (urlConnection instanceof HttpsURLConnection && sslSocketFactory != null) {
|
||||
if (urlConnection instanceof HttpsURLConnection) {
|
||||
final HttpsURLConnection httpsConn = (HttpsURLConnection) urlConnection;
|
||||
final SSLSocketFactory factory = sslSocketFactory;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
|
@ -224,107 +179,8 @@ public class HttpClient extends AbstractLifecycleComponent {
|
|||
return new HttpResponse(statusCode, body, responseHeaders);
|
||||
}
|
||||
|
||||
/** SSL Initialization **/
|
||||
private SSLSocketFactory createSSLSocketFactory(Settings settings) {
|
||||
try {
|
||||
String sslContextProtocol = settings.get(SETTINGS_SSL_PROTOCOL, settings.get(SETTINGS_SSL_SECURITY_PROTOCOL, "TLS"));
|
||||
String keyStore = settings.get(SETTINGS_SSL_KEYSTORE, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE,
|
||||
System.getProperty("javax.net.ssl.keyStore")));
|
||||
String keyStorePassword = settings.get(SETTINGS_SSL_KEYSTORE_PASSWORD, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD,
|
||||
System.getProperty("javax.net.ssl.keyStorePassword")));
|
||||
String keyPassword = settings.get(SETTINGS_SSL_KEYSTORE_KEY_PASSWORD, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD,
|
||||
keyStorePassword));
|
||||
String keyStoreAlgorithm = settings.get(SETTINGS_SSL_KEYSTORE_ALGORITHM, settings.get(SETTINGS_SSL_SECURITY_KEYSTORE_ALGORITHM,
|
||||
System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm())));
|
||||
String trustStore = settings.get(SETTINGS_SSL_TRUSTSTORE, settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE,
|
||||
System.getProperty("javax.net.ssl.trustStore")));
|
||||
String trustStorePassword = settings.get(SETTINGS_SSL_TRUSTSTORE_PASSWORD,
|
||||
settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD, System.getProperty("javax.net.ssl.trustStorePassword")));
|
||||
String trustStoreAlgorithm = settings.get(SETTINGS_SSL_TRUSTSTORE_ALGORITHM,
|
||||
settings.get(SETTINGS_SSL_SECURITY_TRUSTSTORE_ALGORITHM,
|
||||
System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())));
|
||||
|
||||
if (keyStore != null) {
|
||||
if (trustStore == null) {
|
||||
logger.debug("keystore defined with no truststore defined, using keystore as truststore");
|
||||
trustStore = keyStore;
|
||||
trustStorePassword = keyStorePassword;
|
||||
trustStoreAlgorithm = keyStoreAlgorithm;
|
||||
}
|
||||
} else if (trustStore == null) {
|
||||
logger.debug("no truststore defined, using system default");
|
||||
}
|
||||
|
||||
if (trustStoreAlgorithm == null) {
|
||||
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
}
|
||||
logger.debug("using protocol [{}], keyStore [{}], keyStoreAlgorithm [{}], trustStore [{}] and trustAlgorithm [{}]",
|
||||
sslContextProtocol, keyStore, keyStoreAlgorithm, trustStore, trustStoreAlgorithm);
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance(sslContextProtocol);
|
||||
KeyManager[] keyManagers = keyManagers(env, keyStore, keyStorePassword, keyStoreAlgorithm, keyPassword);
|
||||
TrustManager[] trustManagers = trustManagers(env, trustStore, trustStorePassword, trustStoreAlgorithm);
|
||||
sslContext.init(keyManagers, trustManagers, new SecureRandom());
|
||||
return sslContext.getSocketFactory();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("http client failed to initialize the SSLContext", e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: we shouldn't expose this just for tests
|
||||
public SSLSocketFactory getSslSocketFactory() {
|
||||
return sslSocketFactory;
|
||||
}
|
||||
|
||||
private static KeyManager[] keyManagers(Environment env, String keyStore, String keyStorePassword, String keyStoreAlgorithm,
|
||||
String keyPassword) {
|
||||
if (keyStore == null) {
|
||||
return null;
|
||||
}
|
||||
Path path = env.configFile().resolve(keyStore);
|
||||
if (Files.notExists(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Load KeyStore
|
||||
KeyStore ks = readKeystore(path, keyStorePassword);
|
||||
|
||||
// Initialize KeyManagerFactory
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm);
|
||||
kmf.init(ks, keyPassword.toCharArray());
|
||||
return kmf.getKeyManagers();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("http client failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static TrustManager[] trustManagers(Environment env, String trustStore, String trustStorePassword, String trustStoreAlgorithm) {
|
||||
try {
|
||||
// Load TrustStore
|
||||
KeyStore ks = null;
|
||||
if (trustStore != null) {
|
||||
Path trustStorePath = env.configFile().resolve(trustStore);
|
||||
if (Files.exists(trustStorePath)) {
|
||||
ks = readKeystore(trustStorePath, trustStorePassword);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
return trustFactory.getTrustManagers();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("http client failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyStore readKeystore(Path path, String password) throws Exception {
|
||||
try (InputStream in = Files.newInputStream(path)) {
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert password != null;
|
||||
ks.load(in, password.toCharArray());
|
||||
return ks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
|
@ -30,7 +30,6 @@ import org.bouncycastle.operator.ContentSigner;
|
|||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
|
@ -71,13 +70,21 @@ import java.util.Locale;
|
|||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class CertUtils {
|
||||
/**
|
||||
* Utility methods that deal with {@link Certificate}, {@link KeyStore}, {@link X509ExtendedTrustManager}, {@link X509ExtendedKeyManager}
|
||||
* and other certificate related objects.
|
||||
*/
|
||||
public class CertUtils {
|
||||
|
||||
private static final int SERIAL_BIT_LENGTH = 20 * 8;
|
||||
static final BouncyCastleProvider BC_PROV = new BouncyCastleProvider();
|
||||
|
||||
private CertUtils() {}
|
||||
|
||||
/**
|
||||
* Resolves a path with or without an {@link Environment} as we may be running in a transport client where we do not have access to
|
||||
* the environment
|
||||
*/
|
||||
@SuppressForbidden(reason = "we don't have the environment to resolve files from when running in a transport client")
|
||||
static Path resolvePath(String path, @Nullable Environment environment) {
|
||||
if (environment != null) {
|
||||
|
@ -86,15 +93,21 @@ class CertUtils {
|
|||
return PathUtils.get(Strings.cleanPath(path));
|
||||
}
|
||||
|
||||
static X509ExtendedKeyManager keyManagers(Certificate[] certificateChain, PrivateKey privateKey, char[] password) throws Exception {
|
||||
/**
|
||||
* Returns a {@link X509ExtendedKeyManager} that is built from the provided private key and certificate chain
|
||||
*/
|
||||
static X509ExtendedKeyManager keyManager(Certificate[] certificateChain, PrivateKey privateKey, char[] password) throws Exception {
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
// password must be non-null for keystore...
|
||||
keyStore.setKeyEntry("key", privateKey, password, certificateChain);
|
||||
return keyManagers(keyStore, password, KeyManagerFactory.getDefaultAlgorithm());
|
||||
return keyManager(keyStore, password, KeyManagerFactory.getDefaultAlgorithm());
|
||||
}
|
||||
|
||||
static X509ExtendedKeyManager keyManagers(KeyStore keyStore, char[] password, String algorithm) throws Exception {
|
||||
/**
|
||||
* Returns a {@link X509ExtendedKeyManager} that is built from the provided keystore
|
||||
*/
|
||||
static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm) throws Exception {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||
kmf.init(keyStore, password);
|
||||
KeyManager[] keyManagers = kmf.getKeyManagers();
|
||||
|
@ -106,7 +119,13 @@ class CertUtils {
|
|||
throw new IllegalStateException("failed to find a X509ExtendedKeyManager");
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager trustManagers(Certificate[] certificates) throws Exception {
|
||||
/**
|
||||
* Creates a {@link X509ExtendedTrustManager} based on the provided certificates
|
||||
* @param certificates the certificates to trust
|
||||
* @return a trust manager that trusts the provided certificates
|
||||
* @throws Exception if there is an error loading the certificates or trust manager
|
||||
*/
|
||||
public static X509ExtendedTrustManager trustManager(Certificate[] certificates) throws Exception {
|
||||
KeyStore store = KeyStore.getInstance("jks");
|
||||
store.load(null, null);
|
||||
int counter = 0;
|
||||
|
@ -114,23 +133,33 @@ class CertUtils {
|
|||
store.setCertificateEntry("cert" + counter, certificate);
|
||||
counter++;
|
||||
}
|
||||
return trustManagers(store, TrustManagerFactory.getDefaultAlgorithm());
|
||||
return trustManager(store, TrustManagerFactory.getDefaultAlgorithm());
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager trustManagers(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm,
|
||||
Environment env) throws Exception {
|
||||
/**
|
||||
* Loads the truststore and creates a {@link X509ExtendedTrustManager}
|
||||
* @param trustStorePath the path to the truststore
|
||||
* @param trustStorePassword the password to the truststore
|
||||
* @param trustStoreAlgorithm the algorithm to use for the truststore
|
||||
* @param env the environment to use for file resolution. May be {@code null}
|
||||
* @return a trust manager with the trust material from the store
|
||||
* @throws Exception if an error occurs when loading the truststore or the trust manager
|
||||
*/
|
||||
public static X509ExtendedTrustManager trustManager(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm,
|
||||
@Nullable Environment env) throws Exception {
|
||||
try (InputStream in = Files.newInputStream(resolvePath(trustStorePath, env))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
KeyStore trustStore = KeyStore.getInstance("jks");
|
||||
assert trustStorePassword != null;
|
||||
trustStore.load(in, trustStorePassword.toCharArray());
|
||||
return CertUtils.trustManagers(trustStore, trustStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
return CertUtils.trustManager(trustStore, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager trustManagers(KeyStore keyStore, String algorithm) throws Exception {
|
||||
/**
|
||||
* Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore}
|
||||
*/
|
||||
static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm) throws Exception {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] trustManagers = tmf.getTrustManagers();
|
||||
|
@ -142,7 +171,14 @@ class CertUtils {
|
|||
throw new IllegalStateException("failed to find a X509ExtendedTrustManager");
|
||||
}
|
||||
|
||||
static Certificate[] readCertificates(List<String> certPaths, Environment environment) throws Exception {
|
||||
/**
|
||||
* Reads the provided paths and parses them into {@link Certificate} objects
|
||||
* @param certPaths the paths to the PEM encoded certificates
|
||||
* @param environment the environment to resolve files against. May be {@code null}
|
||||
* @return an array of {@link Certificate} objects
|
||||
* @throws Exception if an error occurs reading a file or parsing a certificate
|
||||
*/
|
||||
public static Certificate[] readCertificates(List<String> certPaths, @Nullable Environment environment) throws Exception {
|
||||
List<Certificate> certificates = new ArrayList<>(certPaths.size());
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
for (String path : certPaths) {
|
||||
|
@ -153,6 +189,9 @@ class CertUtils {
|
|||
return certificates.toArray(new Certificate[certificates.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the certificates from the provided reader
|
||||
*/
|
||||
static void readCertificates(Reader reader, List<Certificate> certificates, CertificateFactory certFactory) throws Exception {
|
||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||
|
||||
|
@ -178,6 +217,9 @@ class CertUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the private key from the reader and optionally uses the password supplier to retrieve a password if the key is encrypted
|
||||
*/
|
||||
static PrivateKey readPrivateKey(Reader reader, Supplier<char[]> passwordSupplier) throws Exception {
|
||||
try (PEMParser parser = new PEMParser(reader)) {
|
||||
Object parsed;
|
||||
|
@ -219,17 +261,35 @@ class CertUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a CA certificate
|
||||
*/
|
||||
static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair) throws Exception {
|
||||
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a signed certificate using the provided CA private key and information from the CA certificate
|
||||
*/
|
||||
static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
|
||||
X509Certificate caCert, PrivateKey caPrivKey) throws Exception {
|
||||
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a signed certificate
|
||||
* @param principal the principal of the certificate; commonly referred to as the distinguished name (DN)
|
||||
* @param subjectAltNames the subject alternative names that should be added to the certificate as an X509v3 extension. May be
|
||||
* {@code null}
|
||||
* @param keyPair the key pair that will be associated with the certificate
|
||||
* @param caCert the CA certificate. If {@code null}, this results in a self signed certificate
|
||||
* @param caPrivKey the CA private key. If {@code null}, this results in a self signed certificate
|
||||
* @param isCa whether or not the generated certificate is a CA
|
||||
* @return a signed {@link X509Certificate}
|
||||
* @throws Exception if an error occurs during the certificate creation
|
||||
*/
|
||||
private static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
|
||||
X509Certificate caCert, PrivateKey caPrivKey, boolean ca) throws Exception {
|
||||
X509Certificate caCert, PrivateKey caPrivKey, boolean isCa) throws Exception {
|
||||
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
|
||||
final DateTime notAfter = notBefore.plusYears(1);
|
||||
final BigInteger serial = CertUtils.getSerial();
|
||||
|
@ -259,7 +319,7 @@ class CertUtils {
|
|||
if (subjectAltNames != null) {
|
||||
builder.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
|
||||
}
|
||||
builder.addExtension(Extension.basicConstraints, ca, new BasicConstraints(ca));
|
||||
builder.addExtension(Extension.basicConstraints, isCa, new BasicConstraints(isCa));
|
||||
|
||||
PrivateKey signingKey = caPrivKey != null ? caPrivKey : keyPair.getPrivate();
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);
|
||||
|
@ -267,6 +327,15 @@ class CertUtils {
|
|||
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a certificate signing request
|
||||
* @param keyPair the key pair that will be associated by the certificate generated from the certificate signing request
|
||||
* @param principal the principal of the certificate; commonly referred to as the distinguished name (DN)
|
||||
* @param sanList the subject alternative names that should be added to the certificate as an X509v3 extension. May be
|
||||
* {@code null}
|
||||
* @return a certificate signing request
|
||||
* @throws Exception if an error occurs generating or signing the CSR
|
||||
*/
|
||||
static PKCS10CertificationRequest generateCSR(KeyPair keyPair, X500Principal principal, GeneralNames sanList) throws Exception {
|
||||
JcaPKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(principal, keyPair.getPublic());
|
||||
if (sanList != null) {
|
||||
|
@ -278,6 +347,9 @@ class CertUtils {
|
|||
return builder.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider(CertUtils.BC_PROV).build(keyPair.getPrivate()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random serial for a certificate that is generated from a {@link SecureRandom}
|
||||
*/
|
||||
static BigInteger getSerial() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
BigInteger serial = new BigInteger(SERIAL_BIT_LENGTH, random);
|
||||
|
@ -285,6 +357,9 @@ class CertUtils {
|
|||
return serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a RSA key pair with the provided key size (in bits)
|
||||
*/
|
||||
static KeyPair generateKeyPair(int keysize) throws Exception {
|
||||
// generate a private key
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
|
@ -292,6 +367,9 @@ class CertUtils {
|
|||
return keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the {@link InetAddress} objects into a {@link GeneralNames} object that is used to represent subject alternative names.
|
||||
*/
|
||||
static GeneralNames getSubjectAlternativeNames(boolean resolveName, Set<InetAddress> addresses) throws Exception {
|
||||
Set<GeneralName> generalNameList = new HashSet<>();
|
||||
for (InetAddress address : addresses) {
|
||||
|
@ -308,7 +386,7 @@ class CertUtils {
|
|||
}
|
||||
|
||||
@SuppressForbidden(reason = "need to use getHostName to resolve DNS name and getHostAddress to ensure we resolved the name")
|
||||
static void addSubjectAlternativeNames(boolean resolveName, InetAddress inetAddress, Set<GeneralName> list) {
|
||||
private static void addSubjectAlternativeNames(boolean resolveName, InetAddress inetAddress, Set<GeneralName> list) {
|
||||
String hostaddress = inetAddress.getHostAddress();
|
||||
String ip = NetworkAddress.format(inetAddress);
|
||||
list.add(new GeneralName(GeneralName.iPAddress, ip));
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a trust configuration that corresponds to the default trusted certificates of the JDK
|
||||
*/
|
||||
class DefaultJDKTrustConfig extends TrustConfig {
|
||||
|
||||
static final DefaultJDKTrustConfig INSTANCE = new DefaultJDKTrustConfig();
|
||||
|
||||
private DefaultJDKTrustConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
try {
|
||||
return CertUtils.trustManager(null, TrustManagerFactory.getDefaultAlgorithm());
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JDK trusted certs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the default trust configuration with the provided {@link TrustConfig}
|
||||
* @param trustConfig the trust configuration to merge with
|
||||
* @return a {@link TrustConfig} that represents a combination of both trust configurations
|
||||
*/
|
||||
static TrustConfig merge(TrustConfig trustConfig) {
|
||||
return new CombiningTrustConfig(trustConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* A trust configuration that is a combination of a trust configuration with the default JDK trust configuration. This trust
|
||||
* configuration returns a trust manager verifies certificates against both the default JDK trusted configurations and the specific
|
||||
* {@link TrustConfig} provided.
|
||||
*/
|
||||
static class CombiningTrustConfig extends TrustConfig {
|
||||
|
||||
private final TrustConfig trustConfig;
|
||||
|
||||
private CombiningTrustConfig(TrustConfig trustConfig) {
|
||||
this.trustConfig = trustConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager trustManager = trustConfig.createTrustManager(environment);
|
||||
X509ExtendedTrustManager defaultTrustManager = INSTANCE.createTrustManager(environment);
|
||||
if (trustManager == null) {
|
||||
return defaultTrustManager;
|
||||
}
|
||||
|
||||
X509Certificate[] firstIssuers = trustManager.getAcceptedIssuers();
|
||||
X509Certificate[] secondIssuers = defaultTrustManager.getAcceptedIssuers();
|
||||
X509Certificate[] acceptedIssuers = new X509Certificate[firstIssuers.length + secondIssuers.length];
|
||||
System.arraycopy(firstIssuers, 0, acceptedIssuers, 0, firstIssuers.length);
|
||||
System.arraycopy(secondIssuers, 0, acceptedIssuers, firstIssuers.length, secondIssuers.length);
|
||||
try {
|
||||
return CertUtils.trustManager(acceptedIssuers);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to create trust manager", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return trustConfig.filesToMonitor(environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Combining Trust Config{first=[" + trustConfig.toString() + "], second=[" + INSTANCE.toString() + "]}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof CombiningTrustConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CombiningTrustConfig that = (CombiningTrustConfig) o;
|
||||
return trustConfig.equals(that.trustConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return trustConfig.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,43 +3,30 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
abstract class KeyConfig extends TrustConfig {
|
||||
|
||||
KeyConfig(boolean includeSystem) {
|
||||
super(includeSystem);
|
||||
}
|
||||
|
||||
static final KeyConfig NONE = new KeyConfig(false) {
|
||||
static final KeyConfig NONE = new KeyConfig() {
|
||||
@Override
|
||||
X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
|
@ -49,6 +36,16 @@ abstract class KeyConfig extends TrustConfig {
|
|||
public String toString() {
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
};
|
||||
|
||||
abstract X509ExtendedKeyManager createKeyManager(@Nullable Environment environment);
|
|
@ -3,11 +3,10 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
|
@ -20,19 +19,29 @@ import java.security.PrivateKey;
|
|||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of a key configuration that is backed by a PEM encoded key file and one or more certificates
|
||||
*/
|
||||
class PEMKeyConfig extends KeyConfig {
|
||||
|
||||
final String keyPath;
|
||||
final String keyPassword;
|
||||
final List<String> certPaths;
|
||||
private final String keyPath;
|
||||
private final String keyPassword;
|
||||
private final String certPath;
|
||||
|
||||
PEMKeyConfig(boolean includeSystem, String keyPath, String keyPassword, List<String> certPaths) {
|
||||
super(includeSystem);
|
||||
this.keyPath = keyPath;
|
||||
/**
|
||||
* Creates a new key configuration backed by the key and certificate chain provided
|
||||
* @param keyPath the path to the key file
|
||||
* @param keyPassword the password for the key. May be {@code null}
|
||||
* @param certChainPath the path to the file containing the certificate chain
|
||||
*/
|
||||
PEMKeyConfig(String keyPath, String keyPassword, String certChainPath) {
|
||||
this.keyPath = Objects.requireNonNull(keyPath, "key file must be specified");
|
||||
this.keyPassword = keyPassword;
|
||||
this.certPaths = certPaths;
|
||||
this.certPath = Objects.requireNonNull(certChainPath, "certificate must be specified");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,8 +50,9 @@ class PEMKeyConfig extends KeyConfig {
|
|||
char[] password = keyPassword == null ? new char[0] : keyPassword.toCharArray();
|
||||
try {
|
||||
PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment));
|
||||
Certificate[] certificateChain = CertUtils.readCertificates(certPaths, environment);
|
||||
return CertUtils.keyManagers(certificateChain, privateKey, password);
|
||||
Certificate[] certificateChain = CertUtils.readCertificates(Collections.singletonList(certPath), environment);
|
||||
// password must be non-null for keystore...
|
||||
return CertUtils.keyManager(certificateChain, privateKey, password);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
} finally {
|
||||
|
@ -52,7 +62,7 @@ class PEMKeyConfig extends KeyConfig {
|
|||
}
|
||||
}
|
||||
|
||||
PrivateKey readPrivateKey(Path keyPath) throws Exception {
|
||||
private PrivateKey readPrivateKey(Path keyPath) throws Exception {
|
||||
char[] password = keyPassword == null ? null : keyPassword.toCharArray();
|
||||
try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) {
|
||||
return CertUtils.readPrivateKey(reader, () -> password);
|
||||
|
@ -64,31 +74,20 @@ class PEMKeyConfig extends KeyConfig {
|
|||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
try {
|
||||
Certificate[] certificates = CertUtils.readCertificates(certPaths, environment);
|
||||
return CertUtils.trustManagers(certificates);
|
||||
Certificate[] certificates = CertUtils.readCertificates(Collections.singletonList(certPath), environment);
|
||||
return CertUtils.trustManager(certificates);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (keyPath == null) {
|
||||
throw new IllegalArgumentException("no key file configured");
|
||||
} else if (certPaths == null || certPaths.isEmpty()) {
|
||||
throw new IllegalArgumentException("no certificate provided");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
List<Path> paths = new ArrayList<>(1 + certPaths.size());
|
||||
List<Path> paths = new ArrayList<>(2);
|
||||
paths.add(CertUtils.resolvePath(keyPath, environment));
|
||||
for (String certPath : certPaths) {
|
||||
paths.add(CertUtils.resolvePath(certPath, environment));
|
||||
}
|
||||
paths.add(CertUtils.resolvePath(certPath, environment));
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ class PEMKeyConfig extends KeyConfig {
|
|||
|
||||
if (keyPath != null ? !keyPath.equals(that.keyPath) : that.keyPath != null) return false;
|
||||
if (keyPassword != null ? !keyPassword.equals(that.keyPassword) : that.keyPassword != null) return false;
|
||||
return certPaths != null ? certPaths.equals(that.certPaths) : that.certPaths == null;
|
||||
return certPath != null ? certPath.equals(that.certPath) : that.certPath == null;
|
||||
|
||||
}
|
||||
|
||||
|
@ -109,14 +108,14 @@ class PEMKeyConfig extends KeyConfig {
|
|||
public int hashCode() {
|
||||
int result = keyPath != null ? keyPath.hashCode() : 0;
|
||||
result = 31 * result + (keyPassword != null ? keyPassword.hashCode() : 0);
|
||||
result = 31 * result + (certPaths != null ? certPaths.hashCode() : 0);
|
||||
result = 31 * result + (certPath != null ? certPath.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "keyPath=[" + keyPath +
|
||||
"], certPaths=[" + Strings.collectionToCommaDelimitedString(certPaths) +
|
||||
"], certPaths=[" + certPath +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -15,33 +15,33 @@ import java.nio.file.Path;
|
|||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of trust configuration that is backed by PEM encoded certificate files.
|
||||
*/
|
||||
class PEMTrustConfig extends TrustConfig {
|
||||
|
||||
final List<String> caPaths;
|
||||
private final List<String> caPaths;
|
||||
|
||||
PEMTrustConfig(boolean includeSystem, List<String> caPaths) {
|
||||
super(includeSystem);
|
||||
this.caPaths = caPaths;
|
||||
/**
|
||||
* Create a new trust configuration that is built from the certificate files
|
||||
* @param caPaths the paths to the certificate files to trust
|
||||
*/
|
||||
PEMTrustConfig(List<String> caPaths) {
|
||||
this.caPaths = Objects.requireNonNull(caPaths, "ca paths must be specified");
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
try {
|
||||
Certificate[] certificates = CertUtils.readCertificates(caPaths, environment);
|
||||
return CertUtils.trustManagers(certificates);
|
||||
return CertUtils.trustManager(certificates);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (caPaths == null) {
|
||||
throw new IllegalArgumentException("no ca paths have been configured");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
List<Path> paths = new ArrayList<>(caPaths.size());
|
|
@ -3,14 +3,17 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The client authentication mode that is used for SSL servers
|
||||
*/
|
||||
public enum SSLClientAuth {
|
||||
|
||||
NO() {
|
||||
NONE() {
|
||||
public boolean enabled() {
|
||||
return false;
|
||||
}
|
||||
|
@ -40,25 +43,27 @@ public enum SSLClientAuth {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return true if client authentication is enabled
|
||||
*/
|
||||
public abstract boolean enabled();
|
||||
|
||||
/**
|
||||
* Configure client authentication of the provided {@link SSLEngine}
|
||||
*/
|
||||
public abstract void configure(SSLEngine engine);
|
||||
|
||||
public static SSLClientAuth parse(String value) {
|
||||
assert value != null;
|
||||
switch (value.toLowerCase(Locale.ROOT)) {
|
||||
case "no":
|
||||
case "false":
|
||||
return NO;
|
||||
|
||||
case "none":
|
||||
return NONE;
|
||||
case "optional":
|
||||
return OPTIONAL;
|
||||
|
||||
case "required":
|
||||
case "true":
|
||||
return REQUIRED;
|
||||
default:
|
||||
throw new IllegalArgumentException("could not resolve ssl client auth. unknown ssl client auth value [" + value + "]");
|
||||
throw new IllegalArgumentException("could not resolve ssl client auth. unknown value [" + value + "]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
|
||||
/**
|
||||
* Represents the configuration for an SSLContext
|
||||
*/
|
||||
class SSLConfiguration {
|
||||
|
||||
// These settings are never registered, but they exist so that we can parse the values defined under grouped settings. Also, some are
|
||||
// implemented as optional settings, which provides a declarative manner for fallback as we typically fallback to values from a
|
||||
// different configuration
|
||||
private static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting("cipher_suites", Collections.emptyList(), s -> s);
|
||||
private static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting("supported_protocols", Collections.emptyList(), s -> s);
|
||||
private static final Setting<Optional<String>> KEYSTORE_PATH_SETTING =
|
||||
new Setting<>("keystore.path", (String) null, Optional::ofNullable);
|
||||
private static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("keystore.password", (String) null, Optional::ofNullable);
|
||||
private static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>("keystore.algorithm",
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
private static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
new Setting<>("keystore.key_password", KEYSTORE_PASSWORD_SETTING, Optional::ofNullable);
|
||||
private static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING =
|
||||
new Setting<>("truststore.path", (String) null, Optional::ofNullable);
|
||||
private static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING =
|
||||
new Setting<>("truststore.password", (String) null, Optional::ofNullable);
|
||||
private static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("truststore.algorithm",
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm",
|
||||
TrustManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
private static final Setting<Optional<String>> KEY_PATH_SETTING =
|
||||
new Setting<>("key", (String) null, Optional::ofNullable);
|
||||
private static final Setting<Optional<String>> KEY_PASSWORD_SETTING =
|
||||
new Setting<>("key_passphrase", (String) null, Optional::ofNullable);
|
||||
private static final Setting<Optional<String>> CERT_SETTING =
|
||||
new Setting<>("certificate", (String) null, Optional::ofNullable);
|
||||
private static final Setting<List<String>> CA_PATHS_SETTING =
|
||||
Setting.listSetting("certificate_authorities", Collections.emptyList(), s -> s);
|
||||
private static final Setting<Optional<SSLClientAuth>> CLIENT_AUTH_SETTING =
|
||||
new Setting<>("client_authentication", (String) null, s -> {
|
||||
if (s == null) {
|
||||
return Optional.ofNullable(null);
|
||||
} else {
|
||||
return Optional.of(SSLClientAuth.parse(s));
|
||||
}
|
||||
});
|
||||
private static final Setting<Optional<VerificationMode>> VERIFICATION_MODE_SETTING = new Setting<>("verification_mode", (String) null,
|
||||
s -> {
|
||||
if (s == null) {
|
||||
return Optional.ofNullable(null);
|
||||
} else {
|
||||
return Optional.of(VerificationMode.parse(s));
|
||||
}
|
||||
});
|
||||
|
||||
private final KeyConfig keyConfig;
|
||||
private final TrustConfig trustConfig;
|
||||
private final List<String> ciphers;
|
||||
private final List<String> supportedProtocols;
|
||||
private final SSLClientAuth sslClientAuth;
|
||||
private final VerificationMode verificationMode;
|
||||
|
||||
/**
|
||||
* Creates a new SSLConfiguration from the given settings. There is no fallback configuration when invoking this constructor so
|
||||
* un-configured aspects will take on their default values.
|
||||
* @param settings the SSL specific settings; only the settings under a *.ssl. prefix
|
||||
*/
|
||||
SSLConfiguration(Settings settings) {
|
||||
this.keyConfig = createKeyConfig(settings, null);
|
||||
this.trustConfig = createTrustConfig(settings, keyConfig, null);
|
||||
this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, XPackSettings.DEFAULT_CIPHERS);
|
||||
this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS);
|
||||
this.sslClientAuth = CLIENT_AUTH_SETTING.get(settings).orElse(XPackSettings.CLIENT_AUTH_DEFAULT);
|
||||
this.verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElse(XPackSettings.VERIFICATION_MODE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SSLConfiguration from the given settings and global/default SSLConfiguration. If the settings do not contain a value
|
||||
* for a given aspect, the value from the global configuration will be used.
|
||||
* @param settings the SSL specific settings; only the settings under a *.ssl. prefix
|
||||
* @param globalSSLConfiguration the default configuration that is used as a fallback
|
||||
*/
|
||||
SSLConfiguration(Settings settings, SSLConfiguration globalSSLConfiguration) {
|
||||
Objects.requireNonNull(globalSSLConfiguration);
|
||||
this.keyConfig = createKeyConfig(settings, globalSSLConfiguration);
|
||||
this.trustConfig = createTrustConfig(settings, keyConfig, globalSSLConfiguration);
|
||||
this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, globalSSLConfiguration.cipherSuites());
|
||||
this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, globalSSLConfiguration.supportedProtocols());
|
||||
this.sslClientAuth = CLIENT_AUTH_SETTING.get(settings).orElse(globalSSLConfiguration.sslClientAuth());
|
||||
this.verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElse(globalSSLConfiguration.verificationMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* The configuration for the key, if any, that will be used as part of this ssl configuration
|
||||
*/
|
||||
KeyConfig keyConfig() {
|
||||
return keyConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* The configuration of trust material that will be used as part of this ssl configuration
|
||||
*/
|
||||
TrustConfig trustConfig() {
|
||||
return trustConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cipher suites that will be used for this ssl configuration
|
||||
*/
|
||||
List<String> cipherSuites() {
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
/**
|
||||
* The protocols that are supported by this configuration
|
||||
*/
|
||||
List<String> supportedProtocols() {
|
||||
return supportedProtocols;
|
||||
}
|
||||
|
||||
/**
|
||||
* The verification mode for this configuration; this mode controls certificate and hostname verification
|
||||
*/
|
||||
VerificationMode verificationMode() {
|
||||
return verificationMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The client auth configuration
|
||||
*/
|
||||
SSLClientAuth sslClientAuth() {
|
||||
return sslClientAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the list of paths to files that back this configuration
|
||||
*/
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
if (keyConfig() == trustConfig()) {
|
||||
return keyConfig().filesToMonitor(environment);
|
||||
}
|
||||
List<Path> paths = new ArrayList<>(keyConfig().filesToMonitor(environment));
|
||||
paths.addAll(trustConfig().filesToMonitor(environment));
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLConfiguration{" +
|
||||
"keyConfig=[" + keyConfig +
|
||||
"], trustConfig=" + trustConfig +
|
||||
"], cipherSuites=[" + ciphers +
|
||||
"], supportedProtocols=[" + supportedProtocols +
|
||||
"], sslClientAuth=[" + sslClientAuth +
|
||||
"], verificationMode=[" + verificationMode +
|
||||
"]}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SSLConfiguration)) return false;
|
||||
|
||||
SSLConfiguration that = (SSLConfiguration) o;
|
||||
|
||||
if (this.keyConfig() != null ? !this.keyConfig().equals(that.keyConfig()) : that.keyConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.trustConfig() != null ? !this.trustConfig().equals(that.trustConfig()) : that.trustConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.cipherSuites() != null ? !this.cipherSuites().equals(that.cipherSuites()) : that.cipherSuites() != null) {
|
||||
return false;
|
||||
}
|
||||
if (!this.supportedProtocols().equals(that.supportedProtocols())) {
|
||||
return false;
|
||||
}
|
||||
if (this.verificationMode() != that.verificationMode()) {
|
||||
return false;
|
||||
}
|
||||
if (this.sslClientAuth() != that.sslClientAuth()) {
|
||||
return false;
|
||||
}
|
||||
return this.supportedProtocols() != null ?
|
||||
this.supportedProtocols().equals(that.supportedProtocols()) : that.supportedProtocols() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.keyConfig() != null ? this.keyConfig().hashCode() : 0;
|
||||
result = 31 * result + (this.trustConfig() != null ? this.trustConfig().hashCode() : 0);
|
||||
result = 31 * result + (this.cipherSuites() != null ? this.cipherSuites().hashCode() : 0);
|
||||
result = 31 * result + (this.supportedProtocols() != null ? this.supportedProtocols().hashCode() : 0);
|
||||
result = 31 * result + this.verificationMode().hashCode();
|
||||
result = 31 * result + this.sslClientAuth().hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static KeyConfig createKeyConfig(Settings settings, SSLConfiguration global) {
|
||||
String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
String keyPath = KEY_PATH_SETTING.get(settings).orElse(null);
|
||||
if (keyPath != null && keyStorePath != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a keystore and key file");
|
||||
} else if (keyStorePath == null && keyPath == null) {
|
||||
if (global != null) {
|
||||
return global.keyConfig();
|
||||
} else if (System.getProperty("javax.net.ssl.keyStore") != null) {
|
||||
return new StoreKeyConfig(System.getProperty("javax.net.ssl.keyStore"),
|
||||
System.getProperty("javax.net.ssl.keyStorePassword", ""), System.getProperty("javax.net.ssl.keyStorePassword", ""),
|
||||
System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
|
||||
System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
|
||||
}
|
||||
return KeyConfig.NONE;
|
||||
}
|
||||
|
||||
if (keyPath != null) {
|
||||
String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String certPath = CERT_SETTING.get(settings).orElse(null);
|
||||
if (certPath == null) {
|
||||
throw new IllegalArgumentException("you must specify the certificates to use with the key");
|
||||
}
|
||||
return new PEMKeyConfig(keyPath, keyPassword, certPath);
|
||||
} else {
|
||||
String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings);
|
||||
String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreKeyConfig(keyStorePath, keyStorePassword, keyStoreKeyPassword, keyStoreAlgorithm, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
private static TrustConfig createTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) {
|
||||
String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
List<String> caPaths = getListOrNull(CA_PATHS_SETTING, settings);
|
||||
if (trustStorePath != null && caPaths != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
|
||||
}
|
||||
|
||||
VerificationMode verificationMode = VERIFICATION_MODE_SETTING.get(settings).orElseGet(() -> {
|
||||
if (global != null) {
|
||||
return global.verificationMode();
|
||||
}
|
||||
return XPackSettings.VERIFICATION_MODE_DEFAULT;
|
||||
});
|
||||
if (verificationMode.isCertificateVerificationEnabled() == false) {
|
||||
return TrustAllConfig.INSTANCE;
|
||||
} else if (caPaths != null) {
|
||||
return new PEMTrustConfig(caPaths);
|
||||
} else if (trustStorePath != null) {
|
||||
String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreTrustConfig(trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
} else if (global == null && System.getProperty("javax.net.ssl.trustStore") != null) {
|
||||
return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"),
|
||||
System.getProperty("javax.net.ssl.trustStorePassword", ""),
|
||||
System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
|
||||
} else if (global != null && keyConfig == global.keyConfig()) {
|
||||
return global.trustConfig();
|
||||
} else if (keyConfig != KeyConfig.NONE) {
|
||||
return DefaultJDKTrustConfig.merge(keyConfig);
|
||||
} else {
|
||||
return DefaultJDKTrustConfig.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getListOrNull(Setting<List<String>> listSetting, Settings settings) {
|
||||
return getListOrDefault(listSetting, settings, null);
|
||||
}
|
||||
|
||||
private static List<String> getListOrDefault(Setting<List<String>> listSetting, Settings settings, List<String> defaultValue) {
|
||||
if (listSetting.exists(settings)) {
|
||||
return listSetting.get(settings);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
@ -12,7 +12,7 @@ import org.elasticsearch.watcher.FileChangesListener;
|
|||
import org.elasticsearch.watcher.FileWatcher;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService.Frequency;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLService.SSLContextHolder;
|
||||
import org.elasticsearch.xpack.ssl.SSLService.SSLContextHolder;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.IOException;
|
|
@ -3,22 +3,19 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Custom;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
@ -45,11 +42,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.Security.settingPrefix;
|
||||
import static org.elasticsearch.xpack.security.authc.Realms.REALMS_GROUPS_SETTINGS;
|
||||
import static org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport.SSL_SETTING;
|
||||
|
||||
/**
|
||||
* Provides access to {@link SSLEngine} and {@link SSLSocketFactory} objects based on a provided configuration. All
|
||||
* configurations loaded by this service must be configured on construction.
|
||||
|
@ -60,13 +52,46 @@ public class SSLService extends AbstractComponent {
|
|||
private final SSLConfiguration globalSSLConfiguration;
|
||||
private final Environment env;
|
||||
|
||||
/**
|
||||
* Create a new SSLService that parses the settings for the ssl contexts that need to be created, creates them, and then caches them
|
||||
* for use later
|
||||
*/
|
||||
public SSLService(Settings settings, Environment environment) {
|
||||
super(settings);
|
||||
this.env = environment;
|
||||
this.globalSSLConfiguration = new Global(settings);
|
||||
this.globalSSLConfiguration = new SSLConfiguration(settings.getByPrefix("xpack.ssl."));
|
||||
this.sslContexts = loadSSLConfigurations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SSLService that supports dynamic creation of SSLContext instances. Instances created by this service will not be
|
||||
* cached and will not be monitored for reloading. This dynamic server does have access to the cached and monitored instances that
|
||||
* have been created during initialization
|
||||
*/
|
||||
public SSLService createDynamicSSLService() {
|
||||
return new SSLService(settings, env) {
|
||||
|
||||
@Override
|
||||
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
|
||||
// we don't need to load anything...
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the existing {@link SSLContextHolder} for the configuration
|
||||
* @throws IllegalArgumentException if not found
|
||||
*/
|
||||
SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) {
|
||||
SSLContextHolder holder = SSLService.this.sslContexts.get(sslConfiguration);
|
||||
if (holder == null) {
|
||||
// normally we'd throw here but let's create a new one that is not cached and will not be monitored for changes!
|
||||
holder = SSLService.this.createSslContext(sslConfiguration);
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SSLSocketFactory} based on the provided settings. The settings are used to identify the ssl configuration that
|
||||
* should be used to create the socket factory. The socket factory will also properly configure the ciphers and protocols on each
|
||||
|
@ -79,7 +104,7 @@ public class SSLService extends AbstractComponent {
|
|||
SSLConfiguration sslConfiguration = sslConfiguration(settings);
|
||||
SSLSocketFactory socketFactory = sslContext(sslConfiguration).getSocketFactory();
|
||||
return new SecuritySSLSocketFactory(socketFactory, sslConfiguration.supportedProtocols().toArray(Strings.EMPTY_ARRAY),
|
||||
supportedCiphers(socketFactory.getSupportedCipherSuites(), sslConfiguration.ciphers(), false));
|
||||
supportedCiphers(socketFactory.getSupportedCipherSuites(), sslConfiguration.cipherSuites(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,28 +114,32 @@ public class SSLService extends AbstractComponent {
|
|||
* will not use hostname verification.
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
|
||||
* a SSLEngine created from the default configuration
|
||||
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
* @return {@link SSLEngine}
|
||||
*/
|
||||
public SSLEngine createSSLEngine(Settings settings) {
|
||||
return createSSLEngine(settings, null, -1);
|
||||
public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings) {
|
||||
return createSSLEngine(settings, fallbackSettings, null, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link SSLEngine} based on the provided settings. The settings are used to identify the ssl configuration that should be
|
||||
* used to create the engine. This SSLEngine can be used for a connection that requires hostname verification assuming the provided
|
||||
* host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verificaton enabled
|
||||
* host and port are correct. The SSLEngine created by this method is most useful for clients with hostname verification enabled
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. An empty settings will return
|
||||
* a SSLEngine created from the default configuration
|
||||
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
* @param host the host of the remote endpoint. If using hostname verification, this should match what is in the remote endpoint's
|
||||
* certificate
|
||||
* @param port the port of the remote endpoint
|
||||
* @return {@link SSLEngine}
|
||||
*/
|
||||
public SSLEngine createSSLEngine(Settings settings, String host, int port) {
|
||||
SSLConfiguration configuration = sslConfiguration(settings);
|
||||
public SSLEngine createSSLEngine(Settings settings, Settings fallbackSettings, String host, int port) {
|
||||
SSLConfiguration configuration = sslConfiguration(settings, fallbackSettings);
|
||||
SSLContext sslContext = sslContext(configuration);
|
||||
SSLEngine sslEngine = sslContext.createSSLEngine(host, port);
|
||||
String[] ciphers = supportedCiphers(sslEngine.getSupportedCipherSuites(), configuration.ciphers(), false);
|
||||
String[] ciphers = supportedCiphers(sslEngine.getSupportedCipherSuites(), configuration.cipherSuites(), false);
|
||||
try {
|
||||
sslEngine.setEnabledCipherSuites(ciphers);
|
||||
} catch (ElasticsearchException e) {
|
||||
|
@ -125,16 +154,61 @@ public class SSLService extends AbstractComponent {
|
|||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("failed setting supported protocols " + Arrays.toString(supportedProtocols), e);
|
||||
}
|
||||
|
||||
if (configuration.verificationMode().isHostnameVerificationEnabled() && host != null) {
|
||||
// By default, a SSLEngine will not perform hostname verification. In order to perform hostname verification
|
||||
// we need to specify a EndpointIdentificationAlgorithm. We use the HTTPS algorithm to prevent against
|
||||
// man in the middle attacks for all of our connections.
|
||||
SSLParameters parameters = new SSLParameters();
|
||||
parameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
sslEngine.setSSLParameters(parameters);
|
||||
}
|
||||
|
||||
// TODO configure using SSLParameters
|
||||
configuration.sslClientAuth().configure(sslEngine);
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provided settings results in a valid configuration that can be used for server connections
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix
|
||||
* @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
*/
|
||||
public boolean isConfigurationValidForServerUsage(Settings settings) {
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings);
|
||||
public boolean isConfigurationValidForServerUsage(Settings settings, Settings fallback) {
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
||||
return sslConfiguration.keyConfig() != KeyConfig.NONE;
|
||||
}
|
||||
/**
|
||||
* Indicates whether client authentication is enabled for a particular configuration
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix. The global configuration
|
||||
* will be used for fallback
|
||||
*/
|
||||
public boolean isSSLClientAuthEnabled(Settings settings) {
|
||||
return isSSLClientAuthEnabled(settings, Settings.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether client authentication is enabled for a particular configuration
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix
|
||||
* @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
*/
|
||||
public boolean isSSLClientAuthEnabled(Settings settings, Settings fallback) {
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
||||
return sslConfiguration.sslClientAuth().enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link VerificationMode} that is specified in the settings (or the default)
|
||||
* @param settings the settings used to identify the ssl configuration, typically under a *.ssl. prefix
|
||||
* @param fallback the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
*/
|
||||
public VerificationMode getVerificationMode(Settings settings, Settings fallback) {
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
||||
return sslConfiguration.verificationMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SSLContext} for the global configuration. Mainly used for testing
|
||||
|
@ -171,7 +245,23 @@ public class SSLService extends AbstractComponent {
|
|||
if (settings.isEmpty()) {
|
||||
return globalSSLConfiguration;
|
||||
}
|
||||
return new Custom(settings, globalSSLConfiguration);
|
||||
return new SSLConfiguration(settings, globalSSLConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the existing {@link SSLConfiguration} for the given settings and applies the provided fallback settings instead of the global
|
||||
* configuration
|
||||
* @param settings the settings for the ssl configuration
|
||||
* @param fallbackSettings the settings that should be used for the fallback of the SSLConfiguration. Using {@link Settings#EMPTY}
|
||||
* results in a fallback to the global configuration
|
||||
* @return the ssl configuration for the provided settings. If the settings are empty, the global configuration is returned
|
||||
*/
|
||||
SSLConfiguration sslConfiguration(Settings settings, Settings fallbackSettings) {
|
||||
if (settings.isEmpty() && fallbackSettings.isEmpty()) {
|
||||
return globalSSLConfiguration;
|
||||
}
|
||||
SSLConfiguration fallback = sslConfiguration(fallbackSettings);
|
||||
return new SSLConfiguration(settings, fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,13 +325,11 @@ public class SSLService extends AbstractComponent {
|
|||
|
||||
// Initialize sslContext
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance(sslConfiguration.protocol());
|
||||
SSLContext sslContext = SSLContext.getInstance(sslContextAlgorithm(sslConfiguration.supportedProtocols()));
|
||||
sslContext.init(new X509ExtendedKeyManager[] { keyManager }, new X509ExtendedTrustManager[] { trustManager }, null);
|
||||
sslContext.getServerSessionContext().setSessionCacheSize(sslConfiguration.sessionCacheSize());
|
||||
sslContext.getServerSessionContext().setSessionTimeout(Math.toIntExact(sslConfiguration.sessionCacheTimeout().seconds()));
|
||||
|
||||
// check the supported ciphers and log them here to prevent spamming logs on every call
|
||||
supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), sslConfiguration.ciphers(), true);
|
||||
supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(), sslConfiguration.cipherSuites(), true);
|
||||
|
||||
return new SSLContextHolder(sslContext, trustManager, keyManager);
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
|
@ -252,17 +340,29 @@ public class SSLService extends AbstractComponent {
|
|||
/**
|
||||
* Parses the settings to load all SSLConfiguration objects that will be used.
|
||||
*/
|
||||
private Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
|
||||
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
|
||||
Map<SSLConfiguration, SSLContextHolder> sslConfigurations = new HashMap<>();
|
||||
validateSSLConfiguration(globalSSLConfiguration);
|
||||
sslConfigurations.put(globalSSLConfiguration, createSslContext(globalSSLConfiguration));
|
||||
List<Settings> sslSettings = new ArrayList<>();
|
||||
sslSettings.addAll(getTransportSSLSettings(settings));
|
||||
sslSettings.addAll(getRealmsSSLSettings(settings));
|
||||
sslSettings.addAll(getHttpSSLSettings(settings));
|
||||
for (Settings settings : sslSettings) {
|
||||
SSLConfiguration sslConfiguration = new Custom(settings, globalSSLConfiguration);
|
||||
validateSSLConfiguration(sslConfiguration);
|
||||
|
||||
final Settings transportSSLSettings = settings.getByPrefix("xpack.security.transport.ssl.");
|
||||
List<Settings> sslSettingsList = new ArrayList<>();
|
||||
sslSettingsList.add(transportSSLSettings);
|
||||
sslSettingsList.add(getHttpTransportSSLSettings(settings));
|
||||
sslSettingsList.add(settings.getByPrefix("xpack.http.ssl."));
|
||||
sslSettingsList.addAll(getRealmsSSLSettings(settings));
|
||||
sslSettingsList.addAll(getMonitoringExporterSettings(settings));
|
||||
|
||||
for (Settings sslSettings : sslSettingsList) {
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(sslSettings, globalSSLConfiguration);
|
||||
if (sslConfigurations.containsKey(sslConfiguration) == false) {
|
||||
sslConfigurations.put(sslConfiguration, createSslContext(sslConfiguration));
|
||||
}
|
||||
}
|
||||
|
||||
// transport profiles are special since they fallback is to the transport settings which in turn falls back to global.
|
||||
SSLConfiguration transportSSLConfiguration = new SSLConfiguration(transportSSLSettings, globalSSLConfiguration);
|
||||
for (Settings profileSettings : getTransportProfileSSLSettings(settings)) {
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(profileSettings, transportSSLConfiguration);
|
||||
if (sslConfigurations.containsKey(sslConfiguration) == false) {
|
||||
sslConfigurations.put(sslConfiguration, createSslContext(sslConfiguration));
|
||||
}
|
||||
|
@ -270,11 +370,6 @@ public class SSLService extends AbstractComponent {
|
|||
return Collections.unmodifiableMap(sslConfigurations);
|
||||
}
|
||||
|
||||
private void validateSSLConfiguration(SSLConfiguration configuration) {
|
||||
configuration.keyConfig().validate();
|
||||
configuration.trustConfig().validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* This socket factory wraps an existing SSLSocketFactory and sets the protocols and ciphers on each SSLSocket after it is created. This
|
||||
* is needed even though the SSLContext is configured properly as the configuration does not flow down to the sockets created by the
|
||||
|
@ -599,29 +694,9 @@ public class SSLService extends AbstractComponent {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settings) {
|
||||
settings.add(Global.CIPHERS_SETTING);
|
||||
settings.add(Global.SUPPORTED_PROTOCOLS_SETTING);
|
||||
settings.add(Global.KEYSTORE_PATH_SETTING);
|
||||
settings.add(Global.KEYSTORE_PASSWORD_SETTING);
|
||||
settings.add(Global.KEYSTORE_ALGORITHM_SETTING);
|
||||
settings.add(Global.KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
settings.add(Global.KEY_PATH_SETTING);
|
||||
settings.add(Global.KEY_PASSWORD_SETTING);
|
||||
settings.add(Global.CERT_SETTING);
|
||||
settings.add(Global.TRUSTSTORE_PATH_SETTING);
|
||||
settings.add(Global.TRUSTSTORE_PASSWORD_SETTING);
|
||||
settings.add(Global.TRUSTSTORE_ALGORITHM_SETTING);
|
||||
settings.add(Global.PROTOCOL_SETTING);
|
||||
settings.add(Global.SESSION_CACHE_SIZE_SETTING);
|
||||
settings.add(Global.SESSION_CACHE_TIMEOUT_SETTING);
|
||||
settings.add(Global.CA_PATHS_SETTING);
|
||||
settings.add(Global.INCLUDE_JDK_CERTS_SETTING);
|
||||
}
|
||||
|
||||
private static List<Settings> getRealmsSSLSettings(Settings settings) {
|
||||
List<Settings> sslSettings = new ArrayList<>();
|
||||
Settings realmsSettings = REALMS_GROUPS_SETTINGS.get(settings);
|
||||
Settings realmsSettings = settings.getByPrefix("xpack.security.authc.realms.");
|
||||
for (String name : realmsSettings.names()) {
|
||||
Settings realmSSLSettings = realmsSettings.getAsSettings(name).getByPrefix("ssl.");
|
||||
if (realmSSLSettings.isEmpty() == false) {
|
||||
|
@ -631,23 +706,87 @@ public class SSLService extends AbstractComponent {
|
|||
return sslSettings;
|
||||
}
|
||||
|
||||
private static List<Settings> getTransportSSLSettings(Settings settings) {
|
||||
private static List<Settings> getTransportProfileSSLSettings(Settings settings) {
|
||||
List<Settings> sslSettings = new ArrayList<>();
|
||||
Map<String, Settings> profiles = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
|
||||
for (Entry<String, Settings> entry : profiles.entrySet()) {
|
||||
Settings profileSettings = entry.getValue();
|
||||
final boolean profileSsl = SecurityNetty4Transport.profileSSL(profileSettings, SSL_SETTING.get(settings));
|
||||
if (profileSsl && profileSettings.isEmpty() == false) {
|
||||
sslSettings.add(profileSettings.getByPrefix(settingPrefix()));
|
||||
Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl.");
|
||||
if (profileSettings.isEmpty() == false) {
|
||||
sslSettings.add(profileSettings);
|
||||
}
|
||||
}
|
||||
return sslSettings;
|
||||
}
|
||||
|
||||
private static List<Settings> getHttpSSLSettings(Settings settings) {
|
||||
if (SecurityNetty4HttpServerTransport.SSL_SETTING.get(settings)) {
|
||||
return Collections.singletonList(settings.getByPrefix(setting("http.ssl.")));
|
||||
public static Settings getHttpTransportSSLSettings(Settings settings) {
|
||||
Settings httpSSLSettings = settings.getByPrefix("xpack.security.http.ssl.");
|
||||
if (httpSSLSettings.isEmpty()) {
|
||||
return httpSSLSettings;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
|
||||
Settings.Builder builder = Settings.builder().put(httpSSLSettings);
|
||||
if (builder.get("client_authentication") == null) {
|
||||
builder.put("client_authentication", XPackSettings.HTTP_CLIENT_AUTH_DEFAULT);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static List<Settings> getMonitoringExporterSettings(Settings settings) {
|
||||
List<Settings> sslSettings = new ArrayList<>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
return sslSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the supported protocols to an appropriate ssl context algorithm. We make an attempt to use the "best" algorithm when
|
||||
* possible. The names in this method are taken from the
|
||||
* <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">JCA Standard Algorithm Name
|
||||
* Documentation for Java 8</a>.
|
||||
*/
|
||||
private static String sslContextAlgorithm(List<String> supportedProtocols) {
|
||||
if (supportedProtocols.isEmpty()) {
|
||||
return "TLSv1.2";
|
||||
}
|
||||
|
||||
String algorithm = "SSL";
|
||||
for (String supportedProtocol : supportedProtocols) {
|
||||
switch (supportedProtocol) {
|
||||
case "TLSv1.2":
|
||||
return "TLSv1.2";
|
||||
case "TLSv1.1":
|
||||
if ("TLSv1.2".equals(algorithm) == false) {
|
||||
algorithm = "TLSv1.1";
|
||||
}
|
||||
break;
|
||||
case "TLSv1":
|
||||
switch (algorithm) {
|
||||
case "TLSv1.2":
|
||||
case "TLSv1.1":
|
||||
break;
|
||||
default:
|
||||
algorithm = "TLSv1";
|
||||
}
|
||||
break;
|
||||
case "SSLv3":
|
||||
switch (algorithm) {
|
||||
case "SSLv2":
|
||||
case "SSL":
|
||||
algorithm = "SSLv3";
|
||||
}
|
||||
break;
|
||||
case "SSLv2":
|
||||
case "SSLv2Hello":
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("found unexpected value in supported protocols: " + supportedProtocol);
|
||||
}
|
||||
}
|
||||
return algorithm;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -17,7 +17,11 @@ import java.nio.file.Path;
|
|||
import java.security.KeyStore;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A key configuration that is backed by a {@link KeyStore}
|
||||
*/
|
||||
class StoreKeyConfig extends KeyConfig {
|
||||
|
||||
final String keyStorePath;
|
||||
|
@ -26,11 +30,18 @@ class StoreKeyConfig extends KeyConfig {
|
|||
final String keyPassword;
|
||||
final String trustStoreAlgorithm;
|
||||
|
||||
StoreKeyConfig(boolean includeSystem, String keyStorePath, String keyStorePassword, String keyPassword,
|
||||
String keyStoreAlgorithm, String trustStoreAlgorithm) {
|
||||
super(includeSystem);
|
||||
this.keyStorePath = keyStorePath;
|
||||
this.keyStorePassword = keyStorePassword;
|
||||
/**
|
||||
* Creates a new configuration that can be used to load key and trust material from a {@link KeyStore}
|
||||
* @param keyStorePath the path to the keystore file
|
||||
* @param keyStorePassword the password for the keystore
|
||||
* @param keyPassword the password for the private key in the keystore
|
||||
* @param keyStoreAlgorithm the algorithm for the keystore
|
||||
* @param trustStoreAlgorithm the algorithm to use when loading as a truststore
|
||||
*/
|
||||
StoreKeyConfig(String keyStorePath, String keyStorePassword, String keyPassword, String keyStoreAlgorithm,
|
||||
String trustStoreAlgorithm) {
|
||||
this.keyStorePath = Objects.requireNonNull(keyStorePath, "keystore path must be specified");
|
||||
this.keyStorePassword = Objects.requireNonNull(keyStorePassword, "keystore password must be specified");
|
||||
this.keyPassword = keyPassword;
|
||||
this.keyStoreAlgorithm = keyStoreAlgorithm;
|
||||
this.trustStoreAlgorithm = trustStoreAlgorithm;
|
||||
|
@ -39,34 +50,25 @@ class StoreKeyConfig extends KeyConfig {
|
|||
@Override
|
||||
X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) {
|
||||
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
// TODO remove reliance on JKS since we can use PKCS12 stores in JDK8+...
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert keyStorePassword != null;
|
||||
ks.load(in, keyStorePassword.toCharArray());
|
||||
return CertUtils.keyManagers(ks, keyPassword.toCharArray(), keyStoreAlgorithm);
|
||||
return CertUtils.keyManager(ks, keyPassword.toCharArray(), keyStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
try {
|
||||
return CertUtils.trustManagers(keyStorePath, keyStorePassword, trustStoreAlgorithm, environment);
|
||||
return CertUtils.trustManager(keyStorePath, keyStorePassword, trustStoreAlgorithm, environment);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (keyStorePath == null) {
|
||||
throw new IllegalArgumentException("keystore path must be specified");
|
||||
} else if (keyStorePassword == null) {
|
||||
throw new IllegalArgumentException("no keystore password configured");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.singletonList(CertUtils.resolvePath(keyStorePath, environment));
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -13,41 +13,39 @@ import javax.net.ssl.X509ExtendedTrustManager;
|
|||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Trust configuration that is backed by a {@link java.security.KeyStore}
|
||||
*/
|
||||
class StoreTrustConfig extends TrustConfig {
|
||||
|
||||
final String trustStorePath;
|
||||
final String trustStorePassword;
|
||||
final String trustStoreAlgorithm;
|
||||
|
||||
StoreTrustConfig(boolean includeSystem, String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) {
|
||||
super(includeSystem);
|
||||
/**
|
||||
* Create a new configuration based on the provided parameters
|
||||
* @param trustStorePath the path to the truststore
|
||||
* @param trustStorePassword the password for the truststore
|
||||
* @param trustStoreAlgorithm the algorithm to use for reading the truststore
|
||||
*/
|
||||
StoreTrustConfig(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) {
|
||||
this.trustStorePath = trustStorePath;
|
||||
this.trustStorePassword = trustStorePassword;
|
||||
this.trustStorePassword = trustStorePath != null ?
|
||||
Objects.requireNonNull(trustStorePassword, "truststore password must be specified") : trustStorePassword;
|
||||
this.trustStoreAlgorithm = trustStoreAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager nonSystemTrustManager(@Nullable Environment environment) {
|
||||
if (trustStorePath == null) {
|
||||
return null;
|
||||
}
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
try {
|
||||
return CertUtils.trustManagers(trustStorePath, trustStorePassword, trustStoreAlgorithm, environment);
|
||||
return CertUtils.trustManager(trustStorePath, trustStorePassword, trustStoreAlgorithm, environment);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (trustStorePath != null) {
|
||||
if (trustStorePassword == null) {
|
||||
throw new IllegalArgumentException("no truststore password configured");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
if (trustStorePath == null) {
|
||||
|
@ -66,9 +64,7 @@ class StoreTrustConfig extends TrustConfig {
|
|||
if (trustStorePath != null ? !trustStorePath.equals(that.trustStorePath) : that.trustStorePath != null) return false;
|
||||
if (trustStorePassword != null ? !trustStorePassword.equals(that.trustStorePassword) : that.trustStorePassword != null)
|
||||
return false;
|
||||
return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm ==
|
||||
null;
|
||||
|
||||
return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm == null;
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A trust manager that trusts all certificates
|
||||
*/
|
||||
class TrustAllConfig extends TrustConfig {
|
||||
|
||||
public static final TrustAllConfig INSTANCE = new TrustAllConfig();
|
||||
|
||||
/**
|
||||
* The {@link X509ExtendedTrustManager} that will trust all certificates. All methods are implemented as a no-op and do not throw
|
||||
* exceptions regardless of the certificate presented.
|
||||
*/
|
||||
private static final X509ExtendedTrustManager TRUST_MANAGER = new X509ExtendedTrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
};
|
||||
|
||||
private TrustAllConfig() {
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
return TRUST_MANAGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "trust all";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The configuration of trust material for SSL usage
|
||||
*/
|
||||
abstract class TrustConfig {
|
||||
|
||||
/**
|
||||
* Creates a {@link X509ExtendedTrustManager} based on the provided configuration
|
||||
* @param environment the environment to resolve files against or null in the case of running in a transport client
|
||||
*/
|
||||
abstract X509ExtendedTrustManager createTrustManager(@Nullable Environment environment);
|
||||
|
||||
/**
|
||||
* Returns a list of files that should be monitored for changes
|
||||
* @param environment the environment to resolve files against or null in the case of running in a transport client
|
||||
*/
|
||||
abstract List<Path> filesToMonitor(@Nullable Environment environment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation
|
||||
*/
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation
|
||||
*/
|
||||
public abstract boolean equals(Object o);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation
|
||||
*/
|
||||
public abstract int hashCode();
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents the verification mode to be used for SSL connections.
|
||||
*/
|
||||
public enum VerificationMode {
|
||||
NONE {
|
||||
@Override
|
||||
public boolean isHostnameVerificationEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCertificateVerificationEnabled() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
CERTIFICATE {
|
||||
@Override
|
||||
public boolean isHostnameVerificationEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCertificateVerificationEnabled() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
FULL {
|
||||
@Override
|
||||
public boolean isHostnameVerificationEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCertificateVerificationEnabled() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return true if hostname verification is enabled
|
||||
*/
|
||||
public abstract boolean isHostnameVerificationEnabled();
|
||||
|
||||
/**
|
||||
* @return true if certificate verification is enabled
|
||||
*/
|
||||
public abstract boolean isCertificateVerificationEnabled();
|
||||
|
||||
public static VerificationMode parse(String value) {
|
||||
assert value != null;
|
||||
switch (value.toLowerCase(Locale.ROOT)) {
|
||||
case "none":
|
||||
return NONE;
|
||||
case "certificate":
|
||||
return CERTIFICATE;
|
||||
case "full":
|
||||
return FULL;
|
||||
default:
|
||||
throw new IllegalArgumentException("could not resolve verification mode. unknown value [" + value + "]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.test.junit.annotations.Network;
|
|||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -57,8 +58,7 @@ public class HttpClientTests extends ESTestCase {
|
|||
authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(null)));
|
||||
webServer = startWebServer();
|
||||
webPort = webServer.getPort();
|
||||
httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment);
|
||||
httpClient.start();
|
||||
httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment, new SSLService(environment.settings(), environment));
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -162,24 +162,23 @@ public class HttpClientTests extends ESTestCase {
|
|||
Settings settings;
|
||||
if (randomBoolean()) {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_TRUSTSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_TRUSTSTORE_PASSWORD, "truststore-testnode-only")
|
||||
.put("xpack.http.ssl.truststore.path", resource.toString())
|
||||
.put("xpack.http.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
} else {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_TRUSTSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_TRUSTSTORE_PASSWORD, "truststore-testnode-only")
|
||||
.put("xpack.ssl.truststore.path", resource.toString())
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
}
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment));
|
||||
|
||||
// We can't use the client created above for the server since it is only a truststore
|
||||
HttpClient httpClient2 = new HttpClient(Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE, getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks"))
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode")
|
||||
.build(), authRegistry, environment);
|
||||
httpClient2.start();
|
||||
Settings settings2 = Settings.builder()
|
||||
.put("xpack.http.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks"))
|
||||
.put("xpack.http.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
HttpClient httpClient2 = new HttpClient(settings2, authRegistry, environment, new SSLService(settings2, environment));
|
||||
webServer.useHttps(httpClient2.getSslSocketFactory(), false);
|
||||
|
||||
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
|
||||
|
@ -200,18 +199,17 @@ public class HttpClientTests extends ESTestCase {
|
|||
Settings settings;
|
||||
if (randomBoolean()) {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode")
|
||||
.put("xpack.http.ssl.keystore.path", resource.toString())
|
||||
.put("xpack.http.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
} else {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD, "testnode")
|
||||
.put("xpack.ssl.keystore.path", resource.toString())
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
}
|
||||
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment));
|
||||
webServer.useHttps(new ClientAuthRequiringSSLSocketFactory(httpClient.getSslSocketFactory()), false);
|
||||
|
||||
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
|
||||
|
@ -235,31 +233,30 @@ public class HttpClientTests extends ESTestCase {
|
|||
final boolean watcherSettings = randomBoolean();
|
||||
if (watcherSettings) {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode")
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE_KEY_PASSWORD, "testnode1")
|
||||
.put("xpack.http.ssl.keystore.path", resource.toString())
|
||||
.put("xpack.http.ssl.keystore.password", "testnode")
|
||||
.put("xpack.http.ssl.keystore.key_password", "testnode1")
|
||||
.build();
|
||||
} else {
|
||||
settings = Settings.builder()
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_PASSWORD, "testnode")
|
||||
.put(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD, "testnode1")
|
||||
.put("xpack.ssl.keystore.path", resource.toString())
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.key_password", "testnode1")
|
||||
.build();
|
||||
}
|
||||
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment));
|
||||
assertThat(httpClient.getSslSocketFactory(), notNullValue());
|
||||
|
||||
Settings.Builder badSettings = Settings.builder().put(settings);
|
||||
if (watcherSettings) {
|
||||
badSettings.remove(HttpClient.SETTINGS_SSL_KEYSTORE_KEY_PASSWORD);
|
||||
badSettings.remove("xpack.http.ssl.keystore.key_password");
|
||||
} else {
|
||||
badSettings.remove(HttpClient.SETTINGS_SSL_SECURITY_KEYSTORE_KEY_PASSWORD);
|
||||
badSettings.remove("xpack.ssl.keystore.key_password");
|
||||
}
|
||||
|
||||
try {
|
||||
new HttpClient(badSettings.build(), authRegistry, environment).start();
|
||||
new HttpClient(badSettings.build(), authRegistry, environment, new SSLService(badSettings.build(), environment));
|
||||
fail("an exception should have been thrown since the key is not recoverable without the password");
|
||||
} catch (Exception e) {
|
||||
UnrecoverableKeyException rootCause = (UnrecoverableKeyException) ExceptionsHelper.unwrap(e, UnrecoverableKeyException.class);
|
||||
|
@ -294,9 +291,8 @@ public class HttpClientTests extends ESTestCase {
|
|||
|
||||
@Network
|
||||
public void testHttpsWithoutTruststore() throws Exception {
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment);
|
||||
httpClient.start();
|
||||
assertThat(httpClient.getSslSocketFactory(), nullValue());
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment, new SSLService(Settings.EMPTY, environment));
|
||||
assertThat(httpClient.getSslSocketFactory(), notNullValue());
|
||||
|
||||
// Known server with a valid cert from a commercial CA
|
||||
HttpRequest.Builder request = HttpRequest.builder("www.elastic.co", 443).scheme(Scheme.HTTPS);
|
||||
|
@ -309,13 +305,12 @@ public class HttpClientTests extends ESTestCase {
|
|||
@Network
|
||||
public void testHttpsWithoutTruststoreAndSSLIntegrationActive() throws Exception {
|
||||
// Add some settings with SSL prefix to force socket factory creation
|
||||
String setting = (randomBoolean() ? HttpClient.SETTINGS_SSL_PREFIX : HttpClient.SETTINGS_SSL_SECURITY_PREFIX) +
|
||||
String setting = (randomBoolean() ? HttpClient.SETTINGS_SSL_PREFIX : "xpack.ssl.") +
|
||||
"foo.bar";
|
||||
Settings settings = Settings.builder()
|
||||
.put(setting, randomBoolean())
|
||||
.build();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(Settings.EMPTY, environment));
|
||||
assertThat(httpClient.getSslSocketFactory(), notNullValue());
|
||||
|
||||
// Known server with a valid cert from a commercial CA
|
||||
|
@ -336,8 +331,7 @@ public class HttpClientTests extends ESTestCase {
|
|||
.put(HttpClient.SETTINGS_PROXY_HOST, "localhost")
|
||||
.put(HttpClient.SETTINGS_PROXY_PORT, proxyServer.getPort())
|
||||
.build();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment));
|
||||
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webPort)
|
||||
.method(HttpMethod.GET)
|
||||
|
@ -365,8 +359,7 @@ public class HttpClientTests extends ESTestCase {
|
|||
.put(HttpClient.SETTINGS_PROXY_HOST, "localhost")
|
||||
.put(HttpClient.SETTINGS_PROXY_PORT, proxyServer.getPort() + 1)
|
||||
.build();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(settings, authRegistry, environment, new SSLService(settings, environment));
|
||||
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webPort)
|
||||
.method(HttpMethod.GET)
|
||||
|
|
|
@ -11,10 +11,8 @@ import org.elasticsearch.common.unit.TimeValue;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequest;
|
||||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
|
@ -29,8 +27,8 @@ public class HttpConnectionTimeoutTests extends ESTestCase {
|
|||
@Network
|
||||
public void testDefaultTimeout() throws Exception {
|
||||
Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment,
|
||||
new SSLService(environment.settings(), environment));
|
||||
|
||||
HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345)
|
||||
.method(HttpMethod.POST)
|
||||
|
@ -56,8 +54,7 @@ public class HttpConnectionTimeoutTests extends ESTestCase {
|
|||
Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
HttpClient httpClient = new HttpClient(Settings.builder()
|
||||
.put("xpack.http.default_connection_timeout", "5s").build()
|
||||
, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
, mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment));
|
||||
|
||||
HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345)
|
||||
.method(HttpMethod.POST)
|
||||
|
@ -83,8 +80,7 @@ public class HttpConnectionTimeoutTests extends ESTestCase {
|
|||
Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
HttpClient httpClient = new HttpClient(Settings.builder()
|
||||
.put("xpack.http.default_connection_timeout", "10s").build()
|
||||
, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
, mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment));
|
||||
|
||||
HttpRequest request = HttpRequest.builder(UNROUTABLE_IP, 12345)
|
||||
.connectionTimeout(TimeValue.timeValueSeconds(5))
|
||||
|
|
|
@ -14,10 +14,8 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequest;
|
||||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -48,8 +46,8 @@ public class HttpReadTimeoutTests extends ESTestCase {
|
|||
|
||||
public void testDefaultTimeout() throws Exception {
|
||||
Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), environment,
|
||||
new SSLService(environment.settings(), environment));
|
||||
|
||||
// we're not going to enqueue an response... so the server will just hang
|
||||
|
||||
|
@ -76,8 +74,7 @@ public class HttpReadTimeoutTests extends ESTestCase {
|
|||
|
||||
HttpClient httpClient = new HttpClient(Settings.builder()
|
||||
.put("xpack.http.default_read_timeout", "3s").build()
|
||||
, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
, mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment));
|
||||
|
||||
final String path = '/' + randomAsciiOfLength(5);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
@ -109,8 +106,7 @@ public class HttpReadTimeoutTests extends ESTestCase {
|
|||
|
||||
HttpClient httpClient = new HttpClient(Settings.builder()
|
||||
.put("xpack.http.default_read_timeout", "10s").build()
|
||||
, mock(HttpAuthRegistry.class), environment);
|
||||
httpClient.start();
|
||||
, mock(HttpAuthRegistry.class), environment, new SSLService(environment.settings(), environment));
|
||||
|
||||
final String path = '/' + randomAsciiOfLength(5);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1String;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
|
@ -24,9 +24,9 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.ssl.CertificateTool.CAInfo;
|
||||
import org.elasticsearch.xpack.security.ssl.CertificateTool.CertificateInformation;
|
||||
import org.elasticsearch.xpack.security.ssl.CertificateTool.Name;
|
||||
import org.elasticsearch.xpack.ssl.CertificateTool.CAInfo;
|
||||
import org.elasticsearch.xpack.ssl.CertificateTool.CertificateInformation;
|
||||
import org.elasticsearch.xpack.ssl.CertificateTool.Name;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.Reader;
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
|
@ -22,8 +22,6 @@ import org.elasticsearch.test.SecurityIntegTestCase;
|
|||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackTransportClient;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
@ -42,16 +40,16 @@ import static org.hamcrest.Matchers.containsString;
|
|||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
public class SslClientAuthTests extends SecurityIntegTestCase {
|
||||
public class SSLClientAuthTests extends SecurityIntegTestCase {
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
// invert the require auth settings
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(SecurityNetty3HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), true)
|
||||
.put("transport.profiles.default.xpack.security.ssl.client.auth", false)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.put("transport.profiles.default.xpack.security.ssl.client_authentication", SSLClientAuth.NONE)
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.build();
|
||||
}
|
||||
|
@ -92,9 +90,10 @@ public class SslClientAuthTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.ssl.keystore.path", store)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient-client-profile")
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.NONE)
|
||||
.put("xpack.ssl.keystore.path", store)
|
||||
.put("xpack.ssl.keystore.password", "testclient-client-profile")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(Security.USER_SETTING.getKey(),
|
||||
transportClientUsername() + ":" + new String(transportClientPassword().internalChars()))
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.apache.lucene.util.SetOnce;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
||||
|
@ -14,7 +14,6 @@ import org.elasticsearch.test.ESTestCase;
|
|||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -77,8 +76,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath);
|
||||
final Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.security.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
final Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
||||
|
@ -136,10 +135,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
final Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.security.ssl.key.path", keyPath)
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", certPath)
|
||||
.putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString())
|
||||
.put("xpack.ssl.key", keyPath)
|
||||
.put("xpack.ssl.key_passphrase", "testnode")
|
||||
.put("xpack.ssl.certificate", certPath)
|
||||
.putArray("xpack.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString())
|
||||
.build();
|
||||
final Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
|
@ -201,8 +200,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Path trustStorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
@ -247,9 +246,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.putArray("xpack.security.ssl.ca", clientCertPath.toString())
|
||||
.putArray("xpack.ssl.certificate_authorities", clientCertPath.toString())
|
||||
.put("path.home", createTempDir())
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), false)
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
||||
|
@ -291,8 +289,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Path keystorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
@ -329,10 +327,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), certPath);
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path", keyPath)
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", certPath)
|
||||
.putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString())
|
||||
.put("xpack.ssl.key", keyPath)
|
||||
.put("xpack.ssl.key_passphrase", "testnode")
|
||||
.put("xpack.ssl.certificate", certPath)
|
||||
.putArray("xpack.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString())
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
@ -364,8 +362,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Path trustStorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
@ -397,7 +395,7 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.putArray("xpack.security.ssl.ca", clientCertPath.toString())
|
||||
.putArray("xpack.ssl.certificate_authorities", clientCertPath.toString())
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
|
@ -3,22 +3,23 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Custom;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.xpack.ssl.DefaultJDKTrustConfig.CombiningTrustConfig;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.everyItem;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.isIn;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
@ -26,65 +27,51 @@ import static org.hamcrest.Matchers.sameInstance;
|
|||
public class SSLConfigurationTests extends ESTestCase {
|
||||
|
||||
public void testThatSSLConfigurationHasCorrectDefaults() {
|
||||
SSLConfiguration globalConfig = new Global(Settings.EMPTY);
|
||||
SSLConfiguration globalConfig = new SSLConfiguration(Settings.EMPTY);
|
||||
assertThat(globalConfig.keyConfig(), sameInstance(KeyConfig.NONE));
|
||||
assertThat(globalConfig.trustConfig(), is(not((globalConfig.keyConfig()))));
|
||||
assertThat(globalConfig.trustConfig(), instanceOf(StoreTrustConfig.class));
|
||||
assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL)));
|
||||
assertThat(globalConfig.trustConfig(), instanceOf(DefaultJDKTrustConfig.class));
|
||||
|
||||
SSLConfiguration scopedConfig = new Custom(Settings.EMPTY, globalConfig);
|
||||
SSLConfiguration scopedConfig = new SSLConfiguration(Settings.EMPTY, globalConfig);
|
||||
assertThat(scopedConfig.keyConfig(), sameInstance(globalConfig.keyConfig()));
|
||||
assertThat(scopedConfig.trustConfig(), sameInstance(globalConfig.trustConfig()));
|
||||
assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL)));
|
||||
}
|
||||
|
||||
public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() {
|
||||
final String path = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks").toString();
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path")
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.put("keystore.path", path)
|
||||
.put("keystore.password", "testnode")
|
||||
.build();
|
||||
Settings profileSettings = settings.getByPrefix("xpack.security.ssl.");
|
||||
// Pass settings in as component settings
|
||||
SSLConfiguration globalSettings = new Global(settings);
|
||||
SSLConfiguration scopedSettings = new Custom(profileSettings, globalSettings);
|
||||
SSLConfiguration globalSettings = new SSLConfiguration(settings);
|
||||
SSLConfiguration scopedSettings = new SSLConfiguration(settings, globalSettings);
|
||||
SSLConfiguration scopedEmptyGlobalSettings =
|
||||
new Custom(profileSettings, new Global(Settings.EMPTY));
|
||||
new SSLConfiguration(settings, new SSLConfiguration(Settings.EMPTY));
|
||||
for (SSLConfiguration sslConfiguration : Arrays.asList(globalSettings, scopedSettings, scopedEmptyGlobalSettings)) {
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
|
||||
assertThat(ksKeyInfo.keyStorePath, is(equalTo("path")));
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyStorePath, is(equalTo(path)));
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("testnode")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo(ksKeyInfo.keyStorePassword)));
|
||||
assertThat(ksKeyInfo.keyStoreAlgorithm, is(KeyManagerFactory.getDefaultAlgorithm()));
|
||||
assertThat(sslConfiguration.trustConfig(), is(sameInstance(ksKeyInfo)));
|
||||
assertThat(sslConfiguration.trustConfig(), is(instanceOf(CombiningTrustConfig.class)));
|
||||
assertCombiningTrustConfigContainsCorrectIssuers(sslConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatKeyPasswordCanBeSet() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path")
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "key")
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", "password")
|
||||
.put("keystore.key_password", "key")
|
||||
.build();
|
||||
SSLConfiguration sslConfiguration = new Global(settings);
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(settings);
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo("key")));
|
||||
|
||||
// Pass settings in as profile settings
|
||||
Settings profileSettings = settings.getByPrefix("xpack.security.ssl.");
|
||||
SSLConfiguration sslConfiguration1 = new Custom(profileSettings,
|
||||
randomBoolean() ? sslConfiguration : new Global(Settings.EMPTY));
|
||||
assertThat(sslConfiguration1.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
ksKeyInfo = (StoreKeyConfig) sslConfiguration1.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo("key")));
|
||||
}
|
||||
|
||||
|
||||
|
@ -97,26 +84,20 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
.put("truststore.path", "trust path")
|
||||
.put("truststore.password", "password for trust")
|
||||
.put("truststore.algorithm", "trusted")
|
||||
.put("protocol", "ssl")
|
||||
.put("session.cache_size", "3")
|
||||
.put("session.cache_timeout", "10m")
|
||||
.build();
|
||||
|
||||
Settings serviceSettings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "comp path")
|
||||
.put("xpack.security.ssl.keystore.password", "comp password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "comp key")
|
||||
.put("xpack.security.ssl.keystore.algorithm", "comp algo")
|
||||
.put("xpack.security.ssl.truststore.path", "comp trust path")
|
||||
.put("xpack.security.ssl.truststore.password", "comp password for trust")
|
||||
.put("xpack.security.ssl.truststore.algorithm", "comp trusted")
|
||||
.put("xpack.security.ssl.protocol", "tls")
|
||||
.put("xpack.security.ssl.session.cache_size", "7")
|
||||
.put("xpack.security.ssl.session.cache_timeout", "20m")
|
||||
.put("xpack.ssl.keystore.path", "comp path")
|
||||
.put("xpack.ssl.keystore.password", "comp password")
|
||||
.put("xpack.ssl.keystore.key_password", "comp key")
|
||||
.put("xpack.ssl.keystore.algorithm", "comp algo")
|
||||
.put("xpack.ssl.truststore.path", "comp trust path")
|
||||
.put("xpack.ssl.truststore.password", "comp password for trust")
|
||||
.put("xpack.ssl.truststore.algorithm", "comp trusted")
|
||||
.build();
|
||||
|
||||
SSLConfiguration globalSettings = new Global(serviceSettings);
|
||||
SSLConfiguration sslConfiguration = new Custom(profileSettings, globalSettings);
|
||||
SSLConfiguration globalSettings = new SSLConfiguration(serviceSettings);
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(profileSettings, globalSettings);
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePath, is(equalTo("path")));
|
||||
|
@ -128,41 +109,31 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
assertThat(ksTrustInfo.trustStorePath, is(equalTo("trust path")));
|
||||
assertThat(ksTrustInfo.trustStorePassword, is(equalTo("password for trust")));
|
||||
assertThat(ksTrustInfo.trustStoreAlgorithm, is(equalTo("trusted")));
|
||||
assertThat(sslConfiguration.protocol(), is(equalTo("ssl")));
|
||||
assertThat(sslConfiguration.sessionCacheSize(), is(equalTo(3)));
|
||||
assertThat(sslConfiguration.sessionCacheTimeout(), is(equalTo(TimeValue.timeValueMinutes(10L))));
|
||||
}
|
||||
|
||||
public void testThatEmptySettingsAreEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY);
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
|
||||
SSLConfiguration profileSSLConfiguration = new Custom(Settings.EMPTY, sslConfiguration);
|
||||
SSLConfiguration profileSSLConfiguration = new SSLConfiguration(Settings.EMPTY, sslConfiguration);
|
||||
assertThat(sslConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
|
||||
assertThat(profileSSLConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(profileSSLConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder()
|
||||
.put("keystore.path", "path1")
|
||||
.put("keystore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
|
@ -170,10 +141,14 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
|
||||
.put("truststore.path", "/trust")
|
||||
.put("truststore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder()
|
||||
.put("truststore.path", "/truststore")
|
||||
.put("truststore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
|
@ -181,35 +156,35 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatEmptySettingsHaveSameHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY);
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY);
|
||||
assertThat(sslConfiguration.hashCode(), is(equalTo(sslConfiguration1.hashCode())));
|
||||
|
||||
SSLConfiguration profileSettings = new Custom(Settings.EMPTY, sslConfiguration);
|
||||
SSLConfiguration profileSettings = new SSLConfiguration(Settings.EMPTY, sslConfiguration);
|
||||
assertThat(profileSettings.hashCode(), is(equalTo(sslConfiguration.hashCode())));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder()
|
||||
.put("keystore.path", "path1")
|
||||
.put("keystore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
|
||||
.put("truststore.path", "/trust")
|
||||
.put("truststore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.builder()
|
||||
.put("truststore.path", "/truststore")
|
||||
.put("truststore.password", randomAsciiOfLength(5))
|
||||
.build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
|
@ -217,36 +192,37 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path",
|
||||
.put("key",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"))
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
|
||||
.put("key_passphrase", "testnode")
|
||||
.put("certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
SSLConfiguration config = new SSLConfiguration(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
KeyManager keyManager = keyConfig.createKeyManager(env);
|
||||
assertNotNull(keyManager);
|
||||
assertThat(config.trustConfig(), sameInstance(keyConfig));
|
||||
TrustManager trustManager = keyConfig.createTrustManager(env);
|
||||
assertNotNull(trustManager);
|
||||
assertThat(config.trustConfig(), instanceOf(CombiningTrustConfig.class));
|
||||
assertCombiningTrustConfigContainsCorrectIssuers(config);
|
||||
}
|
||||
|
||||
public void testConfigurationUsingPEMKeyAndTrustFiles() {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path",
|
||||
.put("key",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"))
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
|
||||
.putArray("xpack.security.ssl.ca",
|
||||
.put("key_passphrase", "testnode")
|
||||
.put("certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
|
||||
.putArray("certificate_authorities",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(),
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt").toString())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
SSLConfiguration config = new SSLConfiguration(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
KeyManager keyManager = keyConfig.createKeyManager(env);
|
||||
|
@ -256,4 +232,13 @@ public class SSLConfigurationTests extends ESTestCase {
|
|||
TrustManager trustManager = keyConfig.createTrustManager(env);
|
||||
assertNotNull(trustManager);
|
||||
}
|
||||
|
||||
private void assertCombiningTrustConfigContainsCorrectIssuers(SSLConfiguration sslConfiguration) {
|
||||
X509Certificate[] trustConfAcceptedIssuers = sslConfiguration.trustConfig().createTrustManager(null).getAcceptedIssuers();
|
||||
X509Certificate[] keyConfAcceptedIssuers = sslConfiguration.keyConfig().createTrustManager(null).getAcceptedIssuers();
|
||||
X509Certificate[] defaultAcceptedIssuers = DefaultJDKTrustConfig.INSTANCE.createTrustManager(null).getAcceptedIssuers();
|
||||
assertEquals(keyConfAcceptedIssuers.length + defaultAcceptedIssuers.length, trustConfAcceptedIssuers.length);
|
||||
assertThat(Arrays.asList(keyConfAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers)));
|
||||
assertThat(Arrays.asList(defaultAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers)));
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
|
@ -71,7 +71,7 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
|
|||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith(Security.setting("ssl.")) == false) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
|
|||
builder.put("resource.reload.interval.high", "1s")
|
||||
.put(SecuritySettingsSource.getSSLSettingsForStore(
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode"))
|
||||
.put("xpack.security.ssl.keystore.path", nodeStorePath);
|
||||
.put("xpack.ssl.keystore.path", nodeStorePath);
|
||||
|
||||
if (builder.get("xpack.security.ssl.truststore.path") != null) {
|
||||
builder.put("xpack.security.ssl.truststore.path", nodeStorePath);
|
||||
if (builder.get("xpack.ssl.truststore.path") != null) {
|
||||
builder.put("xpack.ssl.truststore.path", nodeStorePath);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
@ -106,10 +106,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
|
|||
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.security.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.security.ssl.keystore.password", "changeme")
|
||||
.put("xpack.security.ssl.truststore.path", nodeStorePath)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.ssl.keystore.password", "changeme")
|
||||
.put("xpack.ssl.truststore.path", nodeStorePath)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
String node = randomFrom(internalCluster().getNodeNames());
|
||||
SSLService sslService = new SSLService(settings, new Environment(settings));
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ssl;
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
@ -11,17 +11,14 @@ import org.apache.http.impl.client.HttpClients;
|
|||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.nio.file.Path;
|
||||
|
@ -29,11 +26,10 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
@ -53,49 +49,33 @@ public class SSLServiceTests extends ESTestCase {
|
|||
env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
}
|
||||
|
||||
public void testThatInvalidProtocolThrowsException() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "non-existing")
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
try {
|
||||
new SSLService(settings, env);
|
||||
fail("expected an exception");
|
||||
} catch (ElasticsearchException e) {
|
||||
assertThat(e.getMessage(), containsString("failed to initialize the SSLContext"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
|
||||
Path testClientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks");
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("transport.profiles.foo.xpack.security.ssl.truststore.path", testClientStore)
|
||||
.put("transport.profiles.foo.xpack.security.ssl.truststore.password", "testclient")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
|
||||
Settings customTruststoreSettings = Settings.builder()
|
||||
.put("ssl.truststore.path", testClientStore)
|
||||
.put("ssl.truststore.password", "testclient")
|
||||
.put("truststore.path", testClientStore)
|
||||
.put("truststore.password", "testclient")
|
||||
.build();
|
||||
|
||||
SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings);
|
||||
SSLEngine sslEngineWithTruststore = sslService.createSSLEngine(customTruststoreSettings, Settings.EMPTY);
|
||||
assertThat(sslEngineWithTruststore, is(not(nullValue())));
|
||||
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslEngineWithTruststore, is(not(sameInstance(sslEngine))));
|
||||
}
|
||||
|
||||
public void testThatSslContextCachingWorks() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
|
||||
|
@ -109,11 +89,11 @@ public class SSLServiceTests extends ESTestCase {
|
|||
Path differentPasswordsStore =
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.keystore.key_password", "testnode1")
|
||||
.put("xpack.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.key_password", "testnode1")
|
||||
.build();
|
||||
new SSLService(settings, env).createSSLEngine(Settings.EMPTY);
|
||||
new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
}
|
||||
|
||||
public void testIncorrectKeyPasswordThrowsException() throws Exception {
|
||||
|
@ -121,10 +101,10 @@ public class SSLServiceTests extends ESTestCase {
|
|||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-different-passwords.jks");
|
||||
try {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
new SSLService(settings, env).createSSLEngine(Settings.EMPTY);
|
||||
new SSLService(settings, env).createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
fail("expected an exception");
|
||||
} catch (ElasticsearchException e) {
|
||||
assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory"));
|
||||
|
@ -133,108 +113,142 @@ public class SSLServiceTests extends ESTestCase {
|
|||
|
||||
public void testThatSSLv3IsNotEnabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
|
||||
}
|
||||
|
||||
public void testThatSSLSessionCacheHasDefaultLimits() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
|
||||
assertThat(context.getSessionCacheSize(), equalTo(1000));
|
||||
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
|
||||
}
|
||||
|
||||
public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.session.cache_size", "300")
|
||||
.put("xpack.security.ssl.session.cache_timeout", "600s")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
|
||||
assertThat(context.getSessionCacheSize(), equalTo(300));
|
||||
assertThat(context.getSessionTimeout(), equalTo(600));
|
||||
}
|
||||
|
||||
public void testCreateWithoutAnySettingsNotValidForServer() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testCreateWithOnlyTruststoreNotValidForServer() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testCreateWithKeystoreIsValidForServer() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslEngine, notNullValue());
|
||||
}
|
||||
|
||||
public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", testclientStore)
|
||||
.put("xpack.security.ssl.truststore.password", "testclient")
|
||||
.put("xpack.ssl.truststore.path", testclientStore)
|
||||
.put("xpack.ssl.truststore.password", "testclient")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslEngine, notNullValue());
|
||||
}
|
||||
|
||||
public void testCreateWithoutAnySettingsNotValidForServer() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testCreateWithOnlyTruststoreNotValidForServer() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testCreateWithKeystoreIsValidForServer() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testValidForServerWithFallback() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl.")));
|
||||
|
||||
settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put("xpack.security.transport.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.transport.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl.")));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(
|
||||
settings.getByPrefix("xpack.security.transport.ssl."), settings.getByPrefix("xpack.ssl.")));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl.")));
|
||||
}
|
||||
|
||||
public void testGetVerificationMode() {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(XPackSettings.VERIFICATION_MODE_DEFAULT));
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.verification_mode", "none")
|
||||
.put("xpack.security.transport.ssl.verification_mode", "certificate")
|
||||
.put("transport.profiles.foo.xpack.security.ssl.verification_mode", "full")
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(VerificationMode.NONE));
|
||||
assertThat(sslService.getVerificationMode(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY),
|
||||
is(VerificationMode.CERTIFICATE));
|
||||
assertThat(sslService.getVerificationMode(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."),
|
||||
settings.getByPrefix("xpack.security.transport.ssl.")), is(VerificationMode.FULL));
|
||||
assertThat(sslService.getVerificationMode(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl.")),
|
||||
is(VerificationMode.CERTIFICATE));
|
||||
}
|
||||
|
||||
public void testIsSSLClientAuthEnabled() {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY));
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY));
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.client_authentication", "none")
|
||||
.put("xpack.security.transport.ssl.client_authentication", "optional")
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY));
|
||||
assertFalse(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY));
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl.")));
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("xpack.security.transport.ssl."), Settings.EMPTY));
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(settings.getByPrefix("transport.profiles.foo.xpack.security.ssl."),
|
||||
settings.getByPrefix("xpack.security.transport.ssl.")));
|
||||
}
|
||||
|
||||
public void testThatTruststorePasswordIsRequired() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
.build();
|
||||
IllegalArgumentException e =
|
||||
expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env));
|
||||
assertThat(e.getMessage(), is("no truststore password configured"));
|
||||
NullPointerException e =
|
||||
expectThrows(NullPointerException.class, () -> new SSLService(settings, env));
|
||||
assertThat(e.getMessage(), is("truststore password must be specified"));
|
||||
}
|
||||
|
||||
public void testThatKeystorePasswordIsRequired() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.build();
|
||||
IllegalArgumentException e =
|
||||
expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env));
|
||||
assertThat(e.getMessage(), is("no keystore password configured"));
|
||||
NullPointerException e =
|
||||
expectThrows(NullPointerException.class, () -> new SSLService(settings, env));
|
||||
assertThat(e.getMessage(), is("keystore password must be specified"));
|
||||
}
|
||||
|
||||
public void testCiphersAndInvalidCiphersWork() throws Exception {
|
||||
List<String> ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS);
|
||||
List<String> ciphers = new ArrayList<>(XPackSettings.DEFAULT_CIPHERS);
|
||||
ciphers.add("foo");
|
||||
ciphers.add("bar");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.security.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY);
|
||||
SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(engine, is(notNullValue()));
|
||||
String[] enabledCiphers = engine.getEnabledCipherSuites();
|
||||
assertThat(Arrays.asList(enabledCiphers), not(contains("foo", "bar")));
|
||||
|
@ -242,9 +256,9 @@ public class SSLServiceTests extends ESTestCase {
|
|||
|
||||
public void testInvalidCiphersOnlyThrowsException() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.security.ssl.ciphers", new String[] { "foo", "bar" })
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.ssl.cipher_suites", new String[]{"foo", "bar"})
|
||||
.build();
|
||||
IllegalArgumentException e =
|
||||
expectThrows(IllegalArgumentException.class, () -> new SSLService(settings, env));
|
||||
|
@ -253,18 +267,19 @@ public class SSLServiceTests extends ESTestCase {
|
|||
|
||||
public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY);
|
||||
SSLConfiguration config = sslService.sslConfiguration(Settings.EMPTY);
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), config.ciphers(), false);
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), config.cipherSuites(), false);
|
||||
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
|
||||
|
||||
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
|
||||
assertThat(socket.getEnabledCipherSuites(), is(ciphers));
|
||||
assertThat(socket.getEnabledProtocols(), is(config.supportedProtocols().toArray(Strings.EMPTY_ARRAY)));
|
||||
// the order we set the protocols in is not going to be what is returned as internally the JDK may sort the versions
|
||||
assertThat(socket.getEnabledProtocols(), arrayContainingInAnyOrder(config.supportedProtocols().toArray(Strings.EMPTY_ARRAY)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,8 +298,8 @@ public class SSLServiceTests extends ESTestCase {
|
|||
@Network
|
||||
public void testThatSSLContextTrustsJDKTrustedCAs() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.put("xpack.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.ssl.keystore.password", "testclient")
|
||||
.build();
|
||||
SSLContext sslContext = new SSLService(settings, env).sslContext();
|
||||
try (CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build()) {
|
||||
|
@ -292,21 +307,5 @@ public class SSLServiceTests extends ESTestCase {
|
|||
// certs are trusted by default
|
||||
client.execute(new HttpGet("https://www.elastic.co/")).close();
|
||||
}
|
||||
|
||||
settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), "false")
|
||||
.build();
|
||||
sslContext = new SSLService(settings, env).sslContext();
|
||||
try (CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build()) {
|
||||
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
|
||||
// This will result in a SSLHandshakeException because the truststore is the testnodestore, which doesn't
|
||||
// trust any public CAs
|
||||
client.execute(new HttpGet("https://www.elastic.co/"));
|
||||
fail("A SSLHandshakeException should have been thrown here");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(SSLHandshakeException.class));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.watcher.actions.Action;
|
||||
import org.elasticsearch.xpack.watcher.actions.Action.Result.Status;
|
||||
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
|
||||
|
@ -224,8 +225,8 @@ public class WebhookActionTests extends ESTestCase {
|
|||
|
||||
public void testThatSelectingProxyWorks() throws Exception {
|
||||
Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment);
|
||||
httpClient.start();
|
||||
HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, environment,
|
||||
new SSLService(environment.settings(), environment));
|
||||
|
||||
MockWebServer proxyServer = new MockWebServer();
|
||||
try {
|
||||
|
|
|
@ -50,8 +50,8 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
|
|||
Path resource = getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks");
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE, resource.toString())
|
||||
.put(HttpClient.SETTINGS_SSL_KEYSTORE_PASSWORD, "testnode")
|
||||
.put("xpack.http.ssl.keystore.path", resource.toString())
|
||||
.put("xpack.http.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue