security: transport always uses TLS (elastic/elasticsearch#4738)
This commit brings back support an auto-generated certificate and private key for transport traffic. The auto-generated certificate and key can only be used in development mode; when moving to production a key and certificate must be provided. For the edge case of a user not wanting to encrypt their traffic, the user can set the cipher_suites setting to `TLS_RSA_WITH_NULL_SHA256` or a like cipher, but a key/cert is still required. Closes elastic/elasticsearch#4332 Original commit: elastic/x-pack-elasticsearch@b7a1e629f5
This commit is contained in:
parent
8820902f0c
commit
bd04b30acd
|
@ -5,10 +5,12 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack;
|
||||
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.support.ActionFilter;
|
||||
import org.elasticsearch.bootstrap.BootstrapCheck;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
|
@ -89,15 +91,21 @@ 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.SSLBootstrapCheck;
|
||||
import org.elasticsearch.xpack.ssl.SSLConfigurationReloader;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.watcher.Watcher;
|
||||
import org.elasticsearch.xpack.watcher.WatcherFeatureSet;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -176,7 +184,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
protected Watcher watcher;
|
||||
protected Graph graph;
|
||||
|
||||
public XPackPlugin(Settings settings) throws IOException {
|
||||
public XPackPlugin(Settings settings) throws IOException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException,
|
||||
KeyStoreException, DestroyFailedException, OperatorCreationException {
|
||||
this.settings = settings;
|
||||
this.transportClientMode = transportClientMode(settings);
|
||||
this.env = transportClientMode ? null : new Environment(settings);
|
||||
|
@ -498,4 +507,9 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
public UnaryOperator<RestHandler> getRestHandlerWrapper(ThreadContext threadContext) {
|
||||
return security.getRestHandlerWrapper(threadContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BootstrapCheck> getBootstrapChecks() {
|
||||
return security.getBootstrapChecks();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack;
|
||||
|
||||
import org.elasticsearch.common.Booleans;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
|
@ -45,8 +47,20 @@ 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);
|
||||
/**
|
||||
* Legacy setting for enabling or disabling transport ssl. Defaults to true. This is just here to make upgrading easier since the
|
||||
* user needs to set this setting in 5.x to upgrade
|
||||
*/
|
||||
private static final Setting<Boolean> TRANSPORT_SSL_ENABLED =
|
||||
new Setting<>(XPackPlugin.featureSettingPrefix(XPackPlugin.SECURITY) + ".transport.ssl.enabled", (s) -> Boolean.toString(true),
|
||||
(s) -> {
|
||||
final boolean parsed = Booleans.parseBoolean(s);
|
||||
if (parsed == false) {
|
||||
throw new IllegalArgumentException("transport ssl cannot be disabled. Remove setting [" +
|
||||
XPackPlugin.featureSettingPrefix(XPackPlugin.SECURITY) + ".transport.ssl.enabled]");
|
||||
}
|
||||
return true;
|
||||
}, Property.NodeScope, Property.Deprecated);
|
||||
|
||||
/** Setting for enabling or disabling http ssl. Defaults to false. */
|
||||
public static final Setting<Boolean> HTTP_SSL_ENABLED = enabledSetting(XPackPlugin.SECURITY + ".http.ssl", false);
|
||||
|
@ -86,6 +100,7 @@ public class XPackSettings {
|
|||
ALL_SETTINGS.addAll(GLOBAL_SSL.getAllSettings());
|
||||
ALL_SETTINGS.addAll(HTTP_SSL.getAllSettings());
|
||||
ALL_SETTINGS.addAll(TRANSPORT_SSL.getAllSettings());
|
||||
ALL_SETTINGS.add(TRANSPORT_SSL_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.action.ActionRequest;
|
|||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.support.ActionFilter;
|
||||
import org.elasticsearch.action.support.DestructiveOperations;
|
||||
import org.elasticsearch.bootstrap.BootstrapCheck;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
|
@ -125,6 +126,7 @@ import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
|||
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.SSLBootstrapCheck;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
@ -448,6 +450,14 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
return settingsFilter;
|
||||
}
|
||||
|
||||
public List<BootstrapCheck> getBootstrapChecks() {
|
||||
if (enabled) {
|
||||
return Collections.singletonList(new SSLBootstrapCheck(sslService, settings, env));
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public void onIndexModule(IndexModule module) {
|
||||
if (enabled == false) {
|
||||
return;
|
||||
|
|
|
@ -7,7 +7,6 @@ package org.elasticsearch.xpack.security;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -28,7 +27,6 @@ import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
|||
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
|
||||
|
@ -106,10 +104,7 @@ 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", HTTP_SSL_ENABLED.get(settings)));
|
||||
map.put("transport", Collections.singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
|
||||
return map;
|
||||
return Collections.singletonMap("http", Collections.singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
|
||||
}
|
||||
|
||||
static Map<String, Object> auditUsage(@Nullable AuditTrailService auditTrailService) {
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.elasticsearch.xpack.security.user.User;
|
|||
import org.elasticsearch.xpack.common.xcontent.XContentUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.nio.CharBuffer;
|
||||
|
||||
/**
|
||||
* Request to change a user's password.
|
||||
|
@ -44,15 +44,17 @@ public class ChangePasswordRequestBuilder
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password. Note: the char[] passed to this method will be cleared.
|
||||
*/
|
||||
public ChangePasswordRequestBuilder password(char[] password) {
|
||||
Validation.Error error = Validation.Users.validatePassword(password);
|
||||
if (error != null) {
|
||||
ValidationException validationException = new ValidationException();
|
||||
validationException.addValidationError(error.toString());
|
||||
throw validationException;
|
||||
}
|
||||
|
||||
try (SecuredString securedString = new SecuredString(password)) {
|
||||
Validation.Error error = Validation.Users.validatePassword(password);
|
||||
if (error != null) {
|
||||
ValidationException validationException = new ValidationException();
|
||||
validationException.addValidationError(error.toString());
|
||||
throw validationException;
|
||||
}
|
||||
request.passwordHash(Hasher.BCRYPT.hash(securedString));
|
||||
}
|
||||
return this;
|
||||
|
@ -82,10 +84,10 @@ public class ChangePasswordRequestBuilder
|
|||
} else if (User.Fields.PASSWORD.match(currentFieldName)) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
String password = parser.text();
|
||||
char[] passwordChars = password.toCharArray();
|
||||
final char[] passwordChars = password.toCharArray();
|
||||
password(passwordChars);
|
||||
password = null;
|
||||
Arrays.fill(passwordChars, (char) 0);
|
||||
assert CharBuffer.wrap(passwordChars).chars().noneMatch((i) -> (char) i != (char) 0) : "expected password to " +
|
||||
"clear the char[] but it did not!";
|
||||
} else {
|
||||
throw new ElasticsearchParseException(
|
||||
"expected field [{}] to be of type string, but found [{}] instead", currentFieldName, token);
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
|
|||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.gateway.GatewayService;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
|
@ -777,7 +778,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
|
|||
return queueConsumer.peek();
|
||||
}
|
||||
|
||||
private static Client initializeRemoteClient(Settings settings, Logger logger) {
|
||||
Client initializeRemoteClient(Settings settings, Logger logger) {
|
||||
Settings clientSettings = REMOTE_CLIENT_SETTINGS.get(settings);
|
||||
String[] hosts = clientSettings.getAsArray("hosts");
|
||||
if (hosts.length == 0) {
|
||||
|
@ -807,7 +808,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
|
|||
final Settings theClientSetting = clientSettings.filter((s) -> s.startsWith("hosts") == false); // hosts is not a valid setting
|
||||
final TransportClient transportClient = new TransportClient(Settings.builder()
|
||||
.put("node.name", DEFAULT_CLIENT_NAME + "-" + Node.NODE_NAME_SETTING.get(settings))
|
||||
.put(theClientSetting).build(), Settings.EMPTY, Collections.singletonList(XPackPlugin.class), null) {};
|
||||
.put(theClientSetting).build(), Settings.EMPTY, remoteTransportClientPlugins(), null) {};
|
||||
for (Tuple<String, Integer> pair : hostPortPairs) {
|
||||
try {
|
||||
transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(pair.v1()), pair.v2()));
|
||||
|
@ -965,6 +966,11 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
|
|||
}
|
||||
}
|
||||
|
||||
// method for testing to allow different plugins such as mock transport...
|
||||
List<Class<? extends Plugin>> remoteTransportClientPlugins() {
|
||||
return Collections.singletonList(XPackPlugin.class);
|
||||
}
|
||||
|
||||
public static void registerSettings(List<Setting<?>> settings) {
|
||||
settings.add(INDEX_SETTINGS);
|
||||
settings.add(EXCLUDE_EVENT_SETTINGS);
|
||||
|
|
|
@ -41,7 +41,6 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
|
||||
public class PkiRealm extends Realm {
|
||||
|
@ -199,6 +198,7 @@ public class PkiRealm extends Realm {
|
|||
* @param config this realm's configuration
|
||||
* @param sslService the SSLService to use for ssl configurations
|
||||
*/
|
||||
// TODO move this to a Bootstrap check!
|
||||
static void checkSSLEnabled(RealmConfig config, SSLService sslService) {
|
||||
Settings settings = config.globalSettings();
|
||||
|
||||
|
@ -211,10 +211,9 @@ public class PkiRealm extends Realm {
|
|||
}
|
||||
|
||||
// Default Transport
|
||||
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) {
|
||||
if (clientAuthEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -222,9 +221,7 @@ 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 (SecurityNetty4Transport.PROFILE_SSL_SETTING.get(profileSettings)
|
||||
&& sslService.isSSLClientAuthEnabled(
|
||||
SecurityNetty4Transport.profileSslSettings(profileSettings), transportSSLSettings)) {
|
||||
if (sslService.isSSLClientAuthEnabled(SecurityNetty4Transport.profileSslSettings(profileSettings), transportSSLSettings)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchException;
|
|||
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This is not a string but a CharSequence that can be cleared of its memory. Important for handling passwords.
|
||||
|
@ -26,11 +27,11 @@ public class SecuredString implements CharSequence, AutoCloseable {
|
|||
private boolean cleared = false;
|
||||
|
||||
/**
|
||||
* Note: the passed in chars are duplicated
|
||||
* Creates a new SecuredString from the chars. These chars will be cleared when the SecuredString is closed so they should not be
|
||||
* used directly outside of using the SecuredString
|
||||
*/
|
||||
public SecuredString(char[] chars) {
|
||||
this.chars = new char[chars.length];
|
||||
System.arraycopy(chars, 0, this.chars, 0, chars.length);
|
||||
this.chars = Objects.requireNonNull(chars, "chars must not be null!");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +95,7 @@ public class SecuredString implements CharSequence, AutoCloseable {
|
|||
* @return A copy of the internal characters. May be used for caching.
|
||||
*/
|
||||
public char[] copyChars() {
|
||||
throwIfCleared();
|
||||
return Arrays.copyOf(chars, chars.length);
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,10 @@ public class SecurityClient {
|
|||
client.execute(PutUserAction.INSTANCE, request, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the {@link ChangePasswordRequest} with the username and password. Note: the passed in char[] will be cleared by this
|
||||
* method.
|
||||
*/
|
||||
public ChangePasswordRequestBuilder prepareChangePassword(String username, char[] password) {
|
||||
return new ChangePasswordRequestBuilder(client).username(username).password(password);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
|
||||
public class SecurityServerTransportInterceptor extends AbstractComponent implements TransportInterceptor {
|
||||
|
@ -142,10 +141,8 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
|
|||
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
|
||||
Settings profileSettings = entry.getValue();
|
||||
final boolean profileSsl = SecurityNetty4Transport.PROFILE_SSL_SETTING.get(profileSettings);
|
||||
final Settings profileSslSettings = SecurityNetty4Transport.profileSslSettings(profileSettings);
|
||||
final boolean clientAuth = sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings);
|
||||
final boolean extractClientCert = profileSsl && clientAuth;
|
||||
final boolean extractClientCert = sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings);
|
||||
String type = entry.getValue().get(SETTING_NAME, "node");
|
||||
switch (type) {
|
||||
case "client":
|
||||
|
@ -161,9 +158,7 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
|
|||
}
|
||||
|
||||
if (!profileFilters.containsKey(TransportSettings.DEFAULT_PROFILE)) {
|
||||
final boolean profileSsl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
final boolean clientAuth = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
||||
final boolean extractClientCert = profileSsl && clientAuth;
|
||||
final boolean extractClientCert = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
||||
profileFilters.put(TransportSettings.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
|
||||
threadPool.getThreadContext(), extractClientCert, destructiveOperations, reservedRealmEnabled, securityContext));
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
|
|||
HttpSslChannelHandler(Netty4HttpServerTransport transport) {
|
||||
super(transport, detailedErrorsEnabled, threadPool.getThreadContext());
|
||||
this.sslSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) {
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, false) == 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");
|
||||
}
|
||||
|
|
|
@ -15,12 +15,10 @@ 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.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.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
|
@ -31,7 +29,6 @@ import java.net.InetSocketAddress;
|
|||
import java.net.SocketAddress;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -39,12 +36,9 @@ import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
|||
*/
|
||||
public class SecurityNetty4Transport extends Netty4Transport {
|
||||
|
||||
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
|
||||
public SecurityNetty4Transport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays,
|
||||
|
@ -52,7 +46,6 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
@Nullable IPFilter authenticator, SSLService sslService) {
|
||||
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
|
||||
this.authenticator = authenticator;
|
||||
this.ssl = TRANSPORT_SSL_ENABLED.get(settings);
|
||||
this.sslService = sslService;
|
||||
this.transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
}
|
||||
|
@ -77,32 +70,22 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
|
||||
class SecurityServerChannelInitializer extends ServerChannelInitializer {
|
||||
|
||||
private final boolean sslEnabled;
|
||||
private final Settings securityProfileSettings;
|
||||
|
||||
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");
|
||||
}
|
||||
assert sslService.isConfigurationValidForServerUsage(securityProfileSettings, true) :
|
||||
"the ssl configuration is not valid for server use but we are running as a server. this should have been caught by" +
|
||||
" the key config validation";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
if (sslEnabled) {
|
||||
SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings, transportSSLSettings);
|
||||
serverEngine.setUseClientMode(false);
|
||||
ch.pipeline().addFirst(new SslHandler(serverEngine));
|
||||
}
|
||||
SSLEngine serverEngine = sslService.createSSLEngine(securityProfileSettings, transportSSLSettings);
|
||||
serverEngine.setUseClientMode(false);
|
||||
ch.pipeline().addFirst(new SslHandler(serverEngine));
|
||||
if (authenticator != null) {
|
||||
ch.pipeline().addFirst(new IpFilterRemoteAddressFilter(authenticator, name));
|
||||
}
|
||||
|
@ -121,9 +104,7 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
if (ssl) {
|
||||
ch.pipeline().addFirst(new ClientSslHandlerInitializer(transportSSLSettings, sslService, hostnameVerificationEnabled));
|
||||
}
|
||||
ch.pipeline().addFirst(new ClientSslHandlerInitializer(transportSSLSettings, sslService, hostnameVerificationEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ import org.bouncycastle.asn1.x509.Extension;
|
|||
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.asn1.x509.Time;
|
||||
import org.bouncycastle.cert.CertIOException;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
|
@ -27,6 +29,7 @@ import org.bouncycastle.openssl.X509TrustedCertificateBlock;
|
|||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
|
||||
|
@ -48,19 +51,26 @@ import javax.net.ssl.X509ExtendedKeyManager;
|
|||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
|
@ -96,7 +106,8 @@ public class CertUtils {
|
|||
/**
|
||||
* 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 {
|
||||
static X509ExtendedKeyManager keyManager(Certificate[] certificateChain, PrivateKey privateKey, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException {
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
// password must be non-null for keystore...
|
||||
|
@ -107,7 +118,8 @@ public class CertUtils {
|
|||
/**
|
||||
* Returns a {@link X509ExtendedKeyManager} that is built from the provided keystore
|
||||
*/
|
||||
static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm) throws Exception {
|
||||
static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||
kmf.init(keyStore, password);
|
||||
KeyManager[] keyManagers = kmf.getKeyManagers();
|
||||
|
@ -123,9 +135,9 @@ public class CertUtils {
|
|||
* 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 {
|
||||
public static X509ExtendedTrustManager trustManager(Certificate[] certificates)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException {
|
||||
KeyStore store = KeyStore.getInstance("jks");
|
||||
store.load(null, null);
|
||||
int counter = 0;
|
||||
|
@ -143,23 +155,24 @@ public class CertUtils {
|
|||
* @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 {
|
||||
@Nullable Environment env)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException {
|
||||
try (InputStream in = Files.newInputStream(resolvePath(trustStorePath, env))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
KeyStore trustStore = KeyStore.getInstance("jks");
|
||||
assert trustStorePassword != null;
|
||||
trustStore.load(in, trustStorePassword.toCharArray());
|
||||
return CertUtils.trustManager(trustStore, trustStoreAlgorithm);
|
||||
return trustManager(trustStore, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore}
|
||||
*/
|
||||
static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm) throws Exception {
|
||||
static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] trustManagers = tmf.getTrustManagers();
|
||||
|
@ -176,9 +189,9 @@ public class CertUtils {
|
|||
* @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 {
|
||||
public static Certificate[] readCertificates(List<String> certPaths, @Nullable Environment environment)
|
||||
throws CertificateException, IOException {
|
||||
List<Certificate> certificates = new ArrayList<>(certPaths.size());
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
for (String path : certPaths) {
|
||||
|
@ -192,7 +205,8 @@ public class CertUtils {
|
|||
/**
|
||||
* Reads the certificates from the provided reader
|
||||
*/
|
||||
static void readCertificates(Reader reader, List<Certificate> certificates, CertificateFactory certFactory) throws Exception {
|
||||
static void readCertificates(Reader reader, List<Certificate> certificates, CertificateFactory certFactory)
|
||||
throws IOException, CertificateException {
|
||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||
|
||||
Object parsed = pemParser.readObject();
|
||||
|
@ -220,40 +234,31 @@ public 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 {
|
||||
static PrivateKey readPrivateKey(Reader reader, Supplier<char[]> passwordSupplier) throws IOException {
|
||||
try (PEMParser parser = new PEMParser(reader)) {
|
||||
Object parsed;
|
||||
List<Object> list = new ArrayList<>(1);
|
||||
do {
|
||||
parsed = parser.readObject();
|
||||
if (parsed != null) {
|
||||
list.add(parsed);
|
||||
}
|
||||
} while (parsed != null);
|
||||
|
||||
if (list.size() != 1) {
|
||||
throw new IllegalStateException("key file contained [" + list.size() + "] entries, expected one");
|
||||
final Object parsed = parser.readObject();
|
||||
if (parser.readObject() != null) {
|
||||
throw new IllegalStateException("key file contained more that one entry");
|
||||
}
|
||||
|
||||
PrivateKeyInfo privateKeyInfo;
|
||||
Object parsedObject = list.get(0);
|
||||
if (parsedObject instanceof PEMEncryptedKeyPair) {
|
||||
if (parsed instanceof PEMEncryptedKeyPair) {
|
||||
char[] keyPassword = passwordSupplier.get();
|
||||
if (keyPassword == null) {
|
||||
throw new IllegalArgumentException("cannot read encrypted key without a password");
|
||||
}
|
||||
// we have an encrypted key pair so we need to decrypt it
|
||||
PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) parsedObject;
|
||||
PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) parsed;
|
||||
privateKeyInfo = encryptedKeyPair
|
||||
.decryptKeyPair(new JcePEMDecryptorProviderBuilder().setProvider(BC_PROV).build(keyPassword))
|
||||
.getPrivateKeyInfo();
|
||||
} else if (parsedObject instanceof PEMKeyPair) {
|
||||
privateKeyInfo = ((PEMKeyPair) parsedObject).getPrivateKeyInfo();
|
||||
} else if (parsedObject instanceof PrivateKeyInfo) {
|
||||
privateKeyInfo = (PrivateKeyInfo) parsedObject;
|
||||
} else if (parsed instanceof PEMKeyPair) {
|
||||
privateKeyInfo = ((PEMKeyPair) parsed).getPrivateKeyInfo();
|
||||
} else if (parsed instanceof PrivateKeyInfo) {
|
||||
privateKeyInfo = (PrivateKeyInfo) parsed;
|
||||
} else {
|
||||
throw new IllegalArgumentException("parsed an unsupported object [" +
|
||||
parsedObject.getClass().getSimpleName() + "]");
|
||||
parsed.getClass().getSimpleName() + "]");
|
||||
}
|
||||
|
||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
|
||||
|
@ -264,7 +269,8 @@ public class CertUtils {
|
|||
/**
|
||||
* Generates a CA certificate
|
||||
*/
|
||||
static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days) throws Exception {
|
||||
static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days)
|
||||
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
|
||||
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days);
|
||||
}
|
||||
|
||||
|
@ -272,7 +278,8 @@ public class CertUtils {
|
|||
* Generates a signed certificate using the provided CA private key and information from the CA certificate
|
||||
*/
|
||||
public static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
|
||||
X509Certificate caCert, PrivateKey caPrivKey, int days) throws Exception {
|
||||
X509Certificate caCert, PrivateKey caPrivKey, int days)
|
||||
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
|
||||
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days);
|
||||
}
|
||||
|
||||
|
@ -286,11 +293,10 @@ public class CertUtils {
|
|||
* @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 isCa, int days)
|
||||
throws Exception {
|
||||
throws NoSuchAlgorithmException, CertificateException, CertIOException, OperatorCreationException {
|
||||
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
|
||||
if (days < 1) {
|
||||
throw new IllegalArgumentException("the certificate must be valid for at least one day");
|
||||
|
@ -338,9 +344,9 @@ public class CertUtils {
|
|||
* @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 {
|
||||
static PKCS10CertificationRequest generateCSR(KeyPair keyPair, X500Principal principal, GeneralNames sanList)
|
||||
throws IOException, OperatorCreationException {
|
||||
JcaPKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(principal, keyPair.getPublic());
|
||||
if (sanList != null) {
|
||||
ExtensionsGenerator extGen = new ExtensionsGenerator();
|
||||
|
@ -364,7 +370,7 @@ public class CertUtils {
|
|||
/**
|
||||
* Generates a RSA key pair with the provided key size (in bits)
|
||||
*/
|
||||
static KeyPair generateKeyPair(int keysize) throws Exception {
|
||||
static KeyPair generateKeyPair(int keysize) throws NoSuchAlgorithmException {
|
||||
// generate a private key
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(keysize);
|
||||
|
@ -374,7 +380,7 @@ public class CertUtils {
|
|||
/**
|
||||
* 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 {
|
||||
static GeneralNames getSubjectAlternativeNames(boolean resolveName, Set<InetAddress> addresses) throws SocketException {
|
||||
Set<GeneralName> generalNameList = new HashSet<>();
|
||||
for (InetAddress address : addresses) {
|
||||
if (address.isAnyLocalAddress()) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import javax.net.ssl.TrustManagerFactory;
|
|||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -61,68 +62,10 @@ class DefaultJDKTrustConfig extends TrustConfig {
|
|||
* @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();
|
||||
if (trustConfig == null) {
|
||||
return INSTANCE;
|
||||
} else {
|
||||
return new CombiningTrustConfig(Arrays.asList(INSTANCE, trustConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* 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.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.hash.MessageDigests;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.node.Node;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a {@link KeyConfig} that is automatically generated on node startup if necessary. This helps with the default user experience
|
||||
* so that the user does not need to have any knowledge about SSL setup to start a node
|
||||
*/
|
||||
final class GeneratedKeyConfig extends KeyConfig {
|
||||
|
||||
// these values have been generated using openssl
|
||||
// For private key: openssl pkcs8 -in private.pem -inform PEM -nocrypt -topk8 -outform DER | openssl dgst -sha256 -hex
|
||||
// For certificate: openssl x509 -in ca.pem -noout -fingerprint -sha256
|
||||
private static final String PRIVATE_KEY_SHA256 = "eec5bdb422c17c75d3850ffc64a724e52a99ec64366677da2fe4e782d7426e9f";
|
||||
private static final String CA_CERT_FINGERPRINT_SHA256 = "A147166C71EB8B61DADFC5B19ECAC8443BE2DB32A56FC1A73BC1623250738598";
|
||||
|
||||
private final X509ExtendedKeyManager keyManager;
|
||||
private final X509ExtendedTrustManager trustManager;
|
||||
|
||||
GeneratedKeyConfig(Settings settings) throws NoSuchAlgorithmException, IOException, CertificateException, OperatorCreationException,
|
||||
UnrecoverableKeyException, KeyStoreException {
|
||||
final KeyPair keyPair = CertUtils.generateKeyPair(2048);
|
||||
final X500Principal principal = new X500Principal("CN=" + Node.NODE_NAME_SETTING.get(settings));
|
||||
final Certificate caCert = readCACert();
|
||||
final PrivateKey privateKey = readPrivateKey();
|
||||
final GeneralNames generalNames = CertUtils.getSubjectAlternativeNames(false, getLocalAddresses());
|
||||
X509Certificate certificate =
|
||||
CertUtils.generateSignedCertificate(principal, generalNames, keyPair, (X509Certificate) caCert, privateKey, 365);
|
||||
try {
|
||||
privateKey.destroy();
|
||||
} catch (DestroyFailedException e) {
|
||||
// best effort attempt. This is known to fail for RSA keys on the oracle JDK but maybe they'll fix it in ten years or so...
|
||||
}
|
||||
keyManager = CertUtils.keyManager(new Certificate[] { certificate, caCert }, keyPair.getPrivate(), new char[0]);
|
||||
trustManager = CertUtils.trustManager(new Certificate[] { caCert });
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
return trustManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
// no files to watch
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Generated Key Config. DO NOT USE IN PRODUCTION";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(keyManager, trustManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) {
|
||||
return keyManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
List<PrivateKey> privateKeys(@Nullable Environment environment) {
|
||||
try {
|
||||
return Collections.singletonList(readPrivateKey());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("failed to read key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates all of the loopback and link local addresses so these can be used as SubjectAlternativeNames inside the certificate for
|
||||
* a good out of the box experience with TLS
|
||||
*/
|
||||
private Set<InetAddress> getLocalAddresses() throws SocketException {
|
||||
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||
Set<InetAddress> inetAddresses = new HashSet<>();
|
||||
while (networkInterfaces.hasMoreElements()) {
|
||||
NetworkInterface intf = networkInterfaces.nextElement();
|
||||
if (intf.isUp()) {
|
||||
if (intf.isLoopback()) {
|
||||
inetAddresses.addAll(Collections.list(intf.getInetAddresses()));
|
||||
} else {
|
||||
Enumeration<InetAddress> inetAddressEnumeration = intf.getInetAddresses();
|
||||
while (inetAddressEnumeration.hasMoreElements()) {
|
||||
InetAddress inetAddress = inetAddressEnumeration.nextElement();
|
||||
if (inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress()) {
|
||||
inetAddresses.add(inetAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return inetAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the bundled CA private key. This key is used for signing a automatically generated certificate that allows development nodes
|
||||
* to talk to each other on the same machine.
|
||||
*
|
||||
* This private key is the same for every distribution and is only here for a nice out of the box experience. Once in production mode
|
||||
* this key should not be used!
|
||||
*/
|
||||
static PrivateKey readPrivateKey() throws IOException {
|
||||
try (InputStream inputStream = GeneratedKeyConfig.class.getResourceAsStream("private.pem");
|
||||
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||
PrivateKey privateKey = CertUtils.readPrivateKey(reader, () -> null);
|
||||
MessageDigest md = MessageDigests.sha256();
|
||||
final byte[] privateKeyBytes = privateKey.getEncoded();
|
||||
try {
|
||||
final byte[] digest = md.digest(privateKeyBytes);
|
||||
final byte[] expected = hexStringToByteArray(PRIVATE_KEY_SHA256);
|
||||
if (Arrays.equals(digest, expected) == false) {
|
||||
throw new IllegalStateException("private key hash does not match the expected value!");
|
||||
}
|
||||
} finally {
|
||||
Arrays.fill(privateKeyBytes, (byte) 0);
|
||||
}
|
||||
return privateKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the bundled CA certificate
|
||||
*/
|
||||
static Certificate readCACert() throws IOException, CertificateException {
|
||||
try (InputStream inputStream = GeneratedKeyConfig.class.getResourceAsStream("ca.pem");
|
||||
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
List<Certificate> certificateList = new ArrayList<>(1);
|
||||
CertUtils.readCertificates(reader, certificateList, certificateFactory);
|
||||
if (certificateList.size() != 1) {
|
||||
throw new IllegalStateException("expected [1] default CA certificate but found [" + certificateList.size() + "]");
|
||||
}
|
||||
Certificate certificate = certificateList.get(0);
|
||||
final byte[] encoded = MessageDigests.sha256().digest(certificate.getEncoded());
|
||||
final byte[] expected = hexStringToByteArray(CA_CERT_FINGERPRINT_SHA256);
|
||||
if (Arrays.equals(encoded, expected) == false) {
|
||||
throw new IllegalStateException("CA certificate fingerprint does not match!");
|
||||
}
|
||||
return certificateList.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] hexStringToByteArray(String hexString) {
|
||||
if (hexString.length() % 2 != 0) {
|
||||
throw new IllegalArgumentException("String must be an even length");
|
||||
}
|
||||
final int numBytes = hexString.length() / 2;
|
||||
final byte[] data = new byte[numBytes];
|
||||
|
||||
for(int i = 0; i < numBytes; i++) {
|
||||
final int index = i * 2;
|
||||
final int index2 = index + 1;
|
||||
data[i] = (byte) ((Character.digit(hexString.charAt(index), 16) << 4) + Character.digit(hexString.charAt(index2), 16));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.env.Environment;
|
|||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -46,7 +47,14 @@ abstract class KeyConfig extends TrustConfig {
|
|||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<PrivateKey> privateKeys(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
abstract X509ExtendedKeyManager createKeyManager(@Nullable Environment environment);
|
||||
|
||||
abstract List<PrivateKey> privateKeys(@Nullable Environment environment);
|
||||
}
|
||||
|
|
|
@ -8,15 +8,22 @@ package org.elasticsearch.xpack.ssl;
|
|||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -46,30 +53,40 @@ class PEMKeyConfig extends KeyConfig {
|
|||
|
||||
@Override
|
||||
X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) {
|
||||
// password must be non-null for keystore...
|
||||
char[] password = keyPassword == null ? new char[0] : keyPassword.toCharArray();
|
||||
try {
|
||||
PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment));
|
||||
if (privateKey == null) {
|
||||
throw new IllegalArgumentException("private key [" + keyPath + "] could not be loaded");
|
||||
}
|
||||
Certificate[] certificateChain = CertUtils.readCertificates(Collections.singletonList(certPath), environment);
|
||||
// password must be non-null for keystore...
|
||||
return CertUtils.keyManager(certificateChain, privateKey, password);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
} finally {
|
||||
if (password != null) {
|
||||
Arrays.fill(password, (char) 0);
|
||||
try (SecuredString securedKeyPasswordChars = new SecuredString(keyPassword == null ? new char[0] : keyPassword.toCharArray())) {
|
||||
return CertUtils.keyManager(certificateChain, privateKey, securedKeyPasswordChars.internalChars());
|
||||
}
|
||||
} catch (IOException | UnrecoverableKeyException | NoSuchAlgorithmException | CertificateException | KeyStoreException e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} finally {
|
||||
if (password != null) {
|
||||
Arrays.fill(password, (char) 0);
|
||||
}
|
||||
@Override
|
||||
List<PrivateKey> privateKeys(@Nullable Environment environment) {
|
||||
try {
|
||||
return Collections.singletonList(readPrivateKey(CertUtils.resolvePath(keyPath, environment)));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("failed to read key", e);
|
||||
}
|
||||
}
|
||||
|
||||
private PrivateKey readPrivateKey(Path keyPath) throws IOException {
|
||||
try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8);
|
||||
SecuredString securedString = new SecuredString(keyPassword == null ? new char[0] : keyPassword.toCharArray())) {
|
||||
return CertUtils.readPrivateKey(reader, () -> {
|
||||
if (keyPassword == null) {
|
||||
return null;
|
||||
} else {
|
||||
return securedString.internalChars();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.bootstrap.BootstrapCheck;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Bootstrap check to ensure that we only use the generated key config in non-production situations. This class is currently public because
|
||||
* {@link org.elasticsearch.xpack.security.Security} is in a different package and we use package private accessors of the
|
||||
* {@link SSLService} to get the configuration for the node to node transport
|
||||
*/
|
||||
public final class SSLBootstrapCheck implements BootstrapCheck {
|
||||
|
||||
private final SSLService sslService;
|
||||
private final Settings settings;
|
||||
private final Environment environment;
|
||||
|
||||
public SSLBootstrapCheck(SSLService sslService, Settings settings, @Nullable Environment environment) {
|
||||
this.sslService = sslService;
|
||||
this.settings = settings;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check() {
|
||||
final Settings transportSSLSettings = settings.getByPrefix(XPackSettings.TRANSPORT_SSL_PREFIX);
|
||||
return sslService.sslConfiguration(transportSSLSettings).keyConfig() == KeyConfig.NONE
|
||||
|| isDefaultCACertificateTrusted() || isDefaultPrivateKeyUsed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks at all of the trusted certificates to ensure the default CA is not being trusted. We cannot let this happen in production mode
|
||||
*/
|
||||
private boolean isDefaultCACertificateTrusted() {
|
||||
final PublicKey publicKey;
|
||||
try {
|
||||
publicKey = GeneratedKeyConfig.readCACert().getPublicKey();
|
||||
} catch (IOException | CertificateException e) {
|
||||
throw new ElasticsearchException("failed to check default CA", e);
|
||||
}
|
||||
return sslService.getLoadedSSLConfigurations().stream()
|
||||
.flatMap(config -> Stream.of(config.keyConfig().createTrustManager(environment),
|
||||
config.trustConfig().createTrustManager(environment)))
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap((tm) -> Arrays.stream(tm.getAcceptedIssuers()))
|
||||
.anyMatch((cert) -> {
|
||||
try {
|
||||
cert.verify(publicKey);
|
||||
return true;
|
||||
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException
|
||||
| SignatureException e) {
|
||||
// just ignore these
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks at all of the private keys and if there is a key that is equal to the default CA key then we should bail out
|
||||
*/
|
||||
private boolean isDefaultPrivateKeyUsed() {
|
||||
final PrivateKey defaultPrivateKey;
|
||||
try {
|
||||
defaultPrivateKey = GeneratedKeyConfig.readPrivateKey();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("failed to read key", e);
|
||||
}
|
||||
|
||||
return sslService.getLoadedSSLConfigurations().stream()
|
||||
.flatMap(sslConfiguration -> sslConfiguration.keyConfig().privateKeys(environment).stream())
|
||||
.anyMatch(defaultPrivateKey::equals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String errorMessage() {
|
||||
return "Default SSL key and certificate do not provide security; please generate keys and certificates";
|
||||
}
|
||||
}
|
|
@ -7,7 +7,10 @@ package org.elasticsearch.xpack.ssl;
|
|||
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
|
||||
import org.apache.lucene.util.SetOnce;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.CheckedSupplier;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
|
@ -27,13 +30,17 @@ import javax.net.ssl.SSLSocket;
|
|||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
|
@ -56,26 +63,36 @@ public class SSLService extends AbstractComponent {
|
|||
|
||||
private final Map<SSLConfiguration, SSLContextHolder> sslContexts;
|
||||
private final SSLConfiguration globalSSLConfiguration;
|
||||
private final SetOnce<SSLConfiguration> transportSSLConfiguration = new SetOnce<>();
|
||||
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) {
|
||||
public SSLService(Settings settings, Environment environment) throws CertificateException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, IOException, DestroyFailedException, KeyStoreException, OperatorCreationException {
|
||||
super(settings);
|
||||
this.env = environment;
|
||||
this.globalSSLConfiguration = new SSLConfiguration(settings.getByPrefix(XPackSettings.GLOBAL_SSL_PREFIX));
|
||||
this.sslContexts = loadSSLConfigurations();
|
||||
}
|
||||
|
||||
private SSLService(Settings settings, Environment environment, SSLConfiguration globalSSLConfiguration,
|
||||
Map<SSLConfiguration, SSLContextHolder> sslContexts) {
|
||||
super(settings);
|
||||
this.env = environment;
|
||||
this.globalSSLConfiguration = globalSSLConfiguration;
|
||||
this.sslContexts = sslContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return new SSLService(settings, env, globalSSLConfiguration, sslContexts) {
|
||||
|
||||
@Override
|
||||
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
|
||||
|
@ -87,11 +104,12 @@ public class SSLService extends AbstractComponent {
|
|||
* Returns the existing {@link SSLContextHolder} for the configuration
|
||||
* @throws IllegalArgumentException if not found
|
||||
*/
|
||||
@Override
|
||||
SSLContextHolder sslContextHolder(SSLConfiguration sslConfiguration) {
|
||||
SSLContextHolder holder = SSLService.this.sslContexts.get(sslConfiguration);
|
||||
SSLContextHolder holder = 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);
|
||||
holder = createSslContext(sslConfiguration);
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
@ -218,13 +236,16 @@ public class SSLService extends AbstractComponent {
|
|||
/**
|
||||
* 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
|
||||
* @param useTransportFallback if {@code true} this will use the transport configuration for fallback, otherwise the global
|
||||
* configuration will be used
|
||||
*/
|
||||
public boolean isConfigurationValidForServerUsage(Settings settings, Settings fallback) {
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
||||
return sslConfiguration.keyConfig() != KeyConfig.NONE;
|
||||
public boolean isConfigurationValidForServerUsage(Settings settings, boolean useTransportFallback) {
|
||||
SSLConfiguration fallback = useTransportFallback ? transportSSLConfiguration.get() : globalSSLConfiguration;
|
||||
SSLConfiguration sslConfiguration = new SSLConfiguration(settings, fallback);
|
||||
return sslConfiguration.keyConfig() != KeyConfig.NONE
|
||||
|| (useTransportFallback && transportSSLConfiguration.get().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
|
||||
|
@ -368,7 +389,18 @@ public class SSLService extends AbstractComponent {
|
|||
new ReloadableTrustManager(sslConfiguration.trustConfig().createTrustManager(env), sslConfiguration.trustConfig());
|
||||
ReloadableX509KeyManager keyManager =
|
||||
new ReloadableX509KeyManager(sslConfiguration.keyConfig().createKeyManager(env), sslConfiguration.keyConfig());
|
||||
return createSslContext(keyManager, trustManager, sslConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link SSLContext} based on the provided configuration and trust/key managers
|
||||
* @param sslConfiguration the configuration to use for context creation
|
||||
* @param keyManager the key manager to use
|
||||
* @param trustManager the trust manager to use
|
||||
* @return the created SSLContext
|
||||
*/
|
||||
private SSLContextHolder createSslContext(ReloadableX509KeyManager keyManager, ReloadableTrustManager trustManager,
|
||||
SSLConfiguration sslConfiguration) {
|
||||
// Initialize sslContext
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance(sslContextAlgorithm(sslConfiguration.supportedProtocols()));
|
||||
|
@ -386,32 +418,82 @@ public class SSLService extends AbstractComponent {
|
|||
/**
|
||||
* Parses the settings to load all SSLConfiguration objects that will be used.
|
||||
*/
|
||||
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
|
||||
Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() throws CertificateException,
|
||||
UnrecoverableKeyException, NoSuchAlgorithmException, IOException, DestroyFailedException, KeyStoreException,
|
||||
OperatorCreationException {
|
||||
Map<SSLConfiguration, SSLContextHolder> sslConfigurations = new HashMap<>();
|
||||
sslConfigurations.put(globalSSLConfiguration, createSslContext(globalSSLConfiguration));
|
||||
|
||||
final Settings transportSSLSettings = settings.getByPrefix(XPackSettings.TRANSPORT_SSL_PREFIX);
|
||||
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));
|
||||
}
|
||||
}
|
||||
sslSettingsList.forEach((sslSettings) ->
|
||||
sslConfigurations.computeIfAbsent(new SSLConfiguration(sslSettings, globalSSLConfiguration), this::createSslContext));
|
||||
|
||||
// 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));
|
||||
}
|
||||
// transport is special because we want to use a auto-generated key when there isn't one
|
||||
final SSLConfiguration transportSSLConfiguration = new SSLConfiguration(transportSSLSettings, globalSSLConfiguration);
|
||||
this.transportSSLConfiguration.set(transportSSLConfiguration);
|
||||
List<Settings> profileSettings = getTransportProfileSSLSettings(settings);
|
||||
|
||||
// if no key is provided for transport we can auto-generate a key with a signed certificate for development use only. There is a
|
||||
// bootstrap check that prevents this configuration from being use in production (SSLBootstrapCheck)
|
||||
if (transportSSLConfiguration.keyConfig() == KeyConfig.NONE) {
|
||||
// lazily generate key to avoid slowing down startup where we do not need it
|
||||
final GeneratedKeyConfig generatedKeyConfig = new GeneratedKeyConfig(settings);
|
||||
final TrustConfig trustConfig =
|
||||
new TrustConfig.CombiningTrustConfig(Arrays.asList(transportSSLConfiguration.trustConfig(), new TrustConfig() {
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
return generatedKeyConfig.createTrustManager(environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Generated Trust Config. DO NOT USE IN PRODUCTION";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}));
|
||||
X509ExtendedTrustManager extendedTrustManager = trustConfig.createTrustManager(env);
|
||||
ReloadableTrustManager trustManager = new ReloadableTrustManager(extendedTrustManager, trustConfig);
|
||||
ReloadableX509KeyManager keyManager =
|
||||
new ReloadableX509KeyManager(generatedKeyConfig.createKeyManager(env), generatedKeyConfig);
|
||||
sslConfigurations.put(transportSSLConfiguration, createSslContext(keyManager, trustManager, transportSSLConfiguration));
|
||||
profileSettings.forEach((profileSetting) -> {
|
||||
SSLConfiguration configuration = new SSLConfiguration(profileSetting, transportSSLConfiguration);
|
||||
if (configuration.keyConfig() == KeyConfig.NONE) {
|
||||
sslConfigurations.compute(configuration, (conf, holder) -> {
|
||||
if (holder != null && holder.keyManager == keyManager && holder.trustManager == trustManager) {
|
||||
return holder;
|
||||
} else {
|
||||
return createSslContext(keyManager, trustManager, configuration);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sslConfigurations.computeIfAbsent(configuration, this::createSslContext);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sslConfigurations.computeIfAbsent(transportSSLConfiguration, this::createSslContext);
|
||||
profileSettings.forEach((profileSetting) ->
|
||||
sslConfigurations.computeIfAbsent(new SSLConfiguration(profileSetting, transportSSLConfiguration), this::createSslContext));
|
||||
}
|
||||
return Collections.unmodifiableMap(sslConfigurations);
|
||||
}
|
||||
|
|
|
@ -8,14 +8,24 @@ package org.elasticsearch.xpack.ssl;
|
|||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -49,13 +59,13 @@ 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 use PKCS12 stores in JDK8+...
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert keyStorePassword != null;
|
||||
ks.load(in, keyStorePassword.toCharArray());
|
||||
return CertUtils.keyManager(ks, keyPassword.toCharArray(), keyStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
KeyStore ks = getKeyStore(environment);
|
||||
checkKeyStore(ks);
|
||||
try (SecuredString keyPasswordSecuredString = new SecuredString(keyPassword.toCharArray())) {
|
||||
return CertUtils.keyManager(ks, keyPasswordSecuredString.internalChars(), keyStoreAlgorithm);
|
||||
}
|
||||
} catch (IOException | CertificateException | NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +84,54 @@ class StoreKeyConfig extends KeyConfig {
|
|||
return Collections.singletonList(CertUtils.resolvePath(keyStorePath, environment));
|
||||
}
|
||||
|
||||
@Override
|
||||
List<PrivateKey> privateKeys(@Nullable Environment environment) {
|
||||
try {
|
||||
KeyStore keyStore = getKeyStore(environment);
|
||||
try (SecuredString keyPasswordSecuredString = new SecuredString(keyPassword.toCharArray())) {
|
||||
List<PrivateKey> privateKeys = new ArrayList<>();
|
||||
for (Enumeration<String> e = keyStore.aliases(); e.hasMoreElements(); ) {
|
||||
final String alias = e.nextElement();
|
||||
if (keyStore.isKeyEntry(alias)) {
|
||||
Key key = keyStore.getKey(alias, keyPasswordSecuredString.internalChars());
|
||||
if (key instanceof PrivateKey) {
|
||||
privateKeys.add((PrivateKey) key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return privateKeys;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to list keys", e);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore getKeyStore(@Nullable Environment environment)
|
||||
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
|
||||
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) {
|
||||
// TODO remove reliance on JKS since we can use PKCS12 stores in JDK8+...
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
if (keyStorePassword == null) {
|
||||
throw new IllegalArgumentException("keystore password may not be null");
|
||||
}
|
||||
try (SecuredString keyStorePasswordSecuredString = new SecuredString(keyStorePassword.toCharArray())) {
|
||||
ks.load(in, keyStorePasswordSecuredString.internalChars());
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkKeyStore(KeyStore keyStore) throws KeyStoreException {
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (keyStore.isKeyEntry(alias)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("the keystore [" + keyStorePath + "] does not contain a private key entry");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -5,12 +5,18 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The configuration of trust material for SSL usage
|
||||
|
@ -43,4 +49,63 @@ abstract class TrustConfig {
|
|||
* {@inheritDoc}. Declared as abstract to force implementors to provide a custom implementation
|
||||
*/
|
||||
public abstract int hashCode();
|
||||
|
||||
/**
|
||||
* 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 List<TrustConfig> trustConfigs;
|
||||
|
||||
CombiningTrustConfig(List<TrustConfig> trustConfig) {
|
||||
this.trustConfigs = Collections.unmodifiableList(trustConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
|
||||
Optional<TrustConfig> matchAll = trustConfigs.stream().filter(TrustAllConfig.INSTANCE::equals).findAny();
|
||||
if (matchAll.isPresent()) {
|
||||
return matchAll.get().createTrustManager(environment);
|
||||
}
|
||||
|
||||
try {
|
||||
return CertUtils.trustManager(trustConfigs.stream()
|
||||
.flatMap((tc) -> Arrays.stream(tc.createTrustManager(environment).getAcceptedIssuers()))
|
||||
.collect(Collectors.toList())
|
||||
.toArray(new X509Certificate[0]));
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to create trust manager", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return trustConfigs.stream().flatMap((tc) -> tc.filesToMonitor(environment).stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Combining Trust Config{" + trustConfigs.stream().map(TrustConfig::toString).collect(Collectors.joining(", ")) + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof CombiningTrustConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CombiningTrustConfig that = (CombiningTrustConfig) o;
|
||||
return trustConfigs.equals(that.trustConfigs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return trustConfigs.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWDCCAkCgAwIBAgIJANRlkT/I8aROMA0GCSqGSIb3DQEBCwUAMCYxJDAiBgNV
|
||||
BAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9wbWVudCBjYTAeFw0xNzAxMDUxNDUyMDNa
|
||||
Fw00NDA1MjMxNDUyMDNaMCYxJDAiBgNVBAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9w
|
||||
bWVudCBjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALBfQEQYZmPW
|
||||
cAw939i8RRsa27+qxd32ysJu9aKgSEiIDFKU0JwFh6pog1l8frICM4jF0TqILGHv
|
||||
+QbQYsD2e3jYp0cj8dy2+YN6jgTXMf1N8yh6GYXEzRrEKYhqVTHLpZgbhxEFxsws
|
||||
gZiEMHiVxn6h5i4uWDmkp6zt4kHlKgvjtIEzZ1xiXWcS7jJvVPb8r0xUFPDu8Qij
|
||||
BhjxkbkXprzjGEtt4bKqZ8/R+pr+eUuvmApMSMB38dZxDRXxyavbmbJcGDJX+ZKN
|
||||
4OcECH55B/EtxhPxpfFXmX+y5Lh597vkhgitw8Qhayaa8gF16tt4rUgYude9kGSi
|
||||
m3hs6Q9mWM8CAwEAAaOBiDCBhTAdBgNVHQ4EFgQUM6+ZLgmnj1FXHEPejFcpiRR+
|
||||
ANIwVgYDVR0jBE8wTYAUM6+ZLgmnj1FXHEPejFcpiRR+ANKhKqQoMCYxJDAiBgNV
|
||||
BAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9wbWVudCBjYYIJANRlkT/I8aROMAwGA1Ud
|
||||
EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABqgr2p+Ivb3myF56BuiJYYz55Wa
|
||||
ncm4Aqdw6p/A5qkl3pSXu2zbgSfyFvux7Q1+lowIvw4fAOTBcQQpQkYWJmObkCLg
|
||||
HMiKbBreFVqPOqScjTBk6t1g/mOdJXfOognc6QRwfunEBqevNVDT2w3sGlNHooEM
|
||||
3XUPBgyuznE1Olqt7U0tMGsENyBgZv51bUg7ZZCLrV2sdgqc3XYZUqBnttvbBDyU
|
||||
tozgDMoCXLvVHcpWcKsA+ONd0szbSAu1uF0ZfqgaoSslM1ph9ydPbXEvnD5AFO6Y
|
||||
VBTW3v4cnluhrxO6TwRqNo43L5ENqZhtX9gVtzQ54exQsuoKzZ8NO5X1uIA=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAsF9ARBhmY9ZwDD3f2LxFGxrbv6rF3fbKwm71oqBISIgMUpTQ
|
||||
nAWHqmiDWXx+sgIziMXROogsYe/5BtBiwPZ7eNinRyPx3Lb5g3qOBNcx/U3zKHoZ
|
||||
hcTNGsQpiGpVMculmBuHEQXGzCyBmIQweJXGfqHmLi5YOaSnrO3iQeUqC+O0gTNn
|
||||
XGJdZxLuMm9U9vyvTFQU8O7xCKMGGPGRuRemvOMYS23hsqpnz9H6mv55S6+YCkxI
|
||||
wHfx1nENFfHJq9uZslwYMlf5ko3g5wQIfnkH8S3GE/Gl8VeZf7LkuHn3u+SGCK3D
|
||||
xCFrJpryAXXq23itSBi5172QZKKbeGzpD2ZYzwIDAQABAoIBADRpKbzSj2Ktr4BD
|
||||
xsguMk76rUCIq+Ho25npxT69aJ19KERGCrPChO0jv5yQ/UlClDPZrPI60w2LdTIM
|
||||
LLxwwoJHx3XBfbb7/KuQeLGBjU5bop1tozX4JIcGsdzi1ExG2v+XdoydbdTwiNZc
|
||||
udark1/AFpm0le0TO+yMiEbSpasAUetmwmBLl0ld1qOoEFNM4ueLtM0/JE4kQHJC
|
||||
a6a0fS1D+TQsPCdziW80X2hpwCIbg4CF3LqR521SfwIzRscbaXzCzeBNCShJE8Nm
|
||||
Qun91Szze80aaFBBIwMKbppEx5iYCCKeTyO3yswRuZ44+iBe/piB3F/qRKnjBwNS
|
||||
LeL9NOECgYEA4xMUueF8HN23QeC/KZ/6LALwyNBtT7JP7YbW6dvo+3F0KSPxbDL1
|
||||
nMmeOTV8suAlGslsE+GuvPU6M9fUCxpbVnbYH5hEuh0v25WRekFv14H/yEpVF26o
|
||||
OHeilUIzpRTUOndgkmN8cXNp2xkzs2Yp7F2RSlog2kXQOYgC91YmvjECgYEAxtbC
|
||||
OzxUUjebeqnolo8wYur42BievUDqyD9pCnaix+2F59SdLDgirJIOEtv31jjpLaIh
|
||||
nO8akxMCPNwhEgVzelI2k+jJ+Kermi3+tEAnlBBDf/tMEGNav2XE3MnYkDt2jdza
|
||||
fganfhKQwAufyq2lUHC/Slh+xcLPepTef6zFxv8CgYB6ZEJ7ninDdU3dWEIxMWUq
|
||||
a7tUweLpXfbu1Arqqfl97bzqn9D0vNLd215I/6di0qWtNnvmi3Ifrx3b660C/wXU
|
||||
KOJ8xRnmJu0wsgFjn/mkcxFm54nNw3swVGtxf+lORVfO26FVxgHBNLANxBu1yo82
|
||||
M4ioRsQGYjLFj6XpoqnnQQKBgE8RpYlCs1FCdZxwpmIArMAZKj1chPtDLlnVBWM4
|
||||
zABuzpni7WFhLUCsj9YmDMbuOKOB3pX2av3jSDeFXc05x7LzsGpe3rn3iwCzm554
|
||||
CIUTdpQVDSlTKQoFYSRfS7QHQVymX2hQIxi6Lz9/H9rL9Hopa5gX2smvbywSuOvS
|
||||
e49nAoGAM7TQ9iFBsygXxbxh2EL47nw/LBxbDm86TazpSKrHd9pV6Z/Xv870QEf7
|
||||
cZJ9T/KRGkxlK8L6B7uzeckpk4uMWuDRiymnbg2pqk94oELKkh0iLnlGSMf3IPO8
|
||||
qIRFQsQfA3PaU6SG/izaB1lquBRtIj5kAW2ZXI4O9l5V39Y5/n4=
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsF9ARBhmY9ZwDD3f2LxF
|
||||
Gxrbv6rF3fbKwm71oqBISIgMUpTQnAWHqmiDWXx+sgIziMXROogsYe/5BtBiwPZ7
|
||||
eNinRyPx3Lb5g3qOBNcx/U3zKHoZhcTNGsQpiGpVMculmBuHEQXGzCyBmIQweJXG
|
||||
fqHmLi5YOaSnrO3iQeUqC+O0gTNnXGJdZxLuMm9U9vyvTFQU8O7xCKMGGPGRuRem
|
||||
vOMYS23hsqpnz9H6mv55S6+YCkxIwHfx1nENFfHJq9uZslwYMlf5ko3g5wQIfnkH
|
||||
8S3GE/Gl8VeZf7LkuHn3u+SGCK3DxCFrJpryAXXq23itSBi5172QZKKbeGzpD2ZY
|
||||
zwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
|
@ -179,10 +179,6 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
|||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.build();
|
||||
}
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String configRoles() {
|
||||
|
|
|
@ -54,13 +54,11 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
|
|||
|
||||
protected static RealmConfig realmConfig;
|
||||
protected static boolean useGlobalSSL;
|
||||
protected static boolean sslEnabled;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupRealm() {
|
||||
realmConfig = randomFrom(RealmConfig.values());
|
||||
useGlobalSSL = randomBoolean();
|
||||
sslEnabled = randomBoolean();
|
||||
ESLoggerFactory.getLogger("test").info("running test with realm configuration [{}], with direct group to role mapping [{}]. " +
|
||||
"Settings [{}]", realmConfig, realmConfig.mapGroupsAsRoles, realmConfig.settings.getAsMap());
|
||||
}
|
||||
|
@ -74,20 +72,34 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
|
|||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Path nodeFiles = createTempDir();
|
||||
Path store = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(realmConfig.buildSettings(store, "testnode"))
|
||||
Settings.Builder builder = Settings.builder();
|
||||
if (useGlobalSSL) {
|
||||
builder.put(super.nodeSettings(nodeOrdinal).filter((s) -> s.startsWith("xpack.ssl.") == false))
|
||||
.put(sslSettingsForStore(store, "testnode"));
|
||||
} else {
|
||||
builder.put(super.nodeSettings(nodeOrdinal));
|
||||
}
|
||||
builder.put(realmConfig.buildSettings(store, "testnode"))
|
||||
.put(XPACK_SECURITY_AUTHC_REALMS_EXTERNAL + ".files.role_mapping", writeFile(nodeFiles, "role_mapping.yml",
|
||||
configRoleMappings()));
|
||||
if (sslEnabled == false && useGlobalSSL) {
|
||||
builder.put(sslSettingsForStore(store, "testnode"));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return sslEnabled;
|
||||
protected Settings transportClientSettings() {
|
||||
if (useGlobalSSL) {
|
||||
Path store = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
return Settings.builder()
|
||||
.put(super.transportClientSettings().filter((s) -> s.startsWith("xpack.ssl.") == false))
|
||||
.put(sslSettingsForStore(store, "testnode"))
|
||||
.build();
|
||||
} else {
|
||||
return super.transportClientSettings();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return useGlobalSSL == false;
|
||||
}
|
||||
|
||||
protected String configRoleMappings() {
|
||||
|
|
|
@ -145,12 +145,12 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
|||
case SUITE:
|
||||
if (customSecuritySettingsSource == null) {
|
||||
customSecuritySettingsSource =
|
||||
new CustomSecuritySettingsSource(sslTransportEnabled(), createTempDir(), currentClusterScope);
|
||||
new CustomSecuritySettingsSource(useGeneratedSSLConfig(), createTempDir(), currentClusterScope);
|
||||
}
|
||||
break;
|
||||
case TEST:
|
||||
customSecuritySettingsSource =
|
||||
new CustomSecuritySettingsSource(sslTransportEnabled(), createTempDir(), currentClusterScope);
|
||||
new CustomSecuritySettingsSource(useGeneratedSSLConfig(), createTempDir(), currentClusterScope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -291,11 +291,9 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Allows to control whether ssl is enabled or not on the transport layer when the
|
||||
* {@link org.elasticsearch.test.ESIntegTestCase.ClusterScope} is set to
|
||||
* {@link org.elasticsearch.test.ESIntegTestCase.Scope#SUITE} or {@link org.elasticsearch.test.ESIntegTestCase.Scope#TEST}
|
||||
* Allows to control whether ssl key information is auto generated or not on the transport layer
|
||||
*/
|
||||
protected boolean sslTransportEnabled() {
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return randomBoolean();
|
||||
}
|
||||
|
||||
|
@ -309,8 +307,8 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
|||
|
||||
private class CustomSecuritySettingsSource extends SecuritySettingsSource {
|
||||
|
||||
private CustomSecuritySettingsSource(boolean sslTransportEnabled, Path configDir, Scope scope) {
|
||||
super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope);
|
||||
private CustomSecuritySettingsSource(boolean useGeneratedSSLConfig, Path configDir, Scope scope) {
|
||||
super(maxNumberOfNodes(), useGeneratedSSLConfig, configDir, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,36 +74,36 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
private final Path parentFolder;
|
||||
private final String subfolderPrefix;
|
||||
private final byte[] systemKey;
|
||||
private final boolean sslTransportEnabled;
|
||||
private final boolean useGeneratedSSLConfig;
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration.
|
||||
*
|
||||
* @param numOfNodes the number of nodes for proper unicast configuration (can be more than actually available)
|
||||
* @param sslTransportEnabled whether ssl should be enabled on the transport layer or not
|
||||
* @param useGeneratedSSLConfig whether ssl key/cert should be auto-generated
|
||||
* @param parentFolder the parent folder that will contain all of the configuration files that need to be created
|
||||
* @param scope the scope of the test that is requiring an instance of SecuritySettingsSource
|
||||
*/
|
||||
public SecuritySettingsSource(int numOfNodes, boolean sslTransportEnabled, Path parentFolder, Scope scope) {
|
||||
this(numOfNodes, sslTransportEnabled, generateKey(), parentFolder, scope);
|
||||
public SecuritySettingsSource(int numOfNodes, boolean useGeneratedSSLConfig, Path parentFolder, Scope scope) {
|
||||
this(numOfNodes, useGeneratedSSLConfig, generateKey(), parentFolder, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration.
|
||||
*
|
||||
* @param numOfNodes the number of nodes for proper unicast configuration (can be more than actually available)
|
||||
* @param sslTransportEnabled whether ssl should be enabled on the transport layer or not
|
||||
* @param useGeneratedSSLConfig whether ssl key/cert should be auto-generated
|
||||
* @param systemKey the system key that all of the nodes will use to sign messages
|
||||
* @param parentFolder the parent folder that will contain all of the configuration files that need to be created
|
||||
* @param scope the scope of the test that is requiring an instance of SecuritySettingsSource
|
||||
*/
|
||||
public SecuritySettingsSource(int numOfNodes, boolean sslTransportEnabled, byte[] systemKey, Path parentFolder, Scope scope) {
|
||||
public SecuritySettingsSource(int numOfNodes, boolean useGeneratedSSLConfig, byte[] systemKey, Path parentFolder, Scope scope) {
|
||||
super(numOfNodes, DEFAULT_SETTINGS);
|
||||
this.systemKey = systemKey;
|
||||
this.parentFolder = parentFolder;
|
||||
this.subfolderPrefix = scope.name();
|
||||
this.sslTransportEnabled = sslTransportEnabled;
|
||||
this.useGeneratedSSLConfig = useGeneratedSSLConfig;
|
||||
this.hostnameVerificationEnabled = randomBoolean();
|
||||
}
|
||||
|
||||
|
@ -211,10 +211,10 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
"/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, false);
|
||||
useGeneratedSSLConfig, hostnameVerificationEnabled, false);
|
||||
}
|
||||
return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", "testnode",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, false);
|
||||
useGeneratedSSLConfig, hostnameVerificationEnabled, false);
|
||||
}
|
||||
|
||||
public Settings getClientSSLSettings() {
|
||||
|
@ -223,11 +223,11 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
"/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, true);
|
||||
useGeneratedSSLConfig, hostnameVerificationEnabled, true);
|
||||
}
|
||||
|
||||
return getSSLSettingsForStore("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", "testclient",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, true);
|
||||
useGeneratedSSLConfig, hostnameVerificationEnabled, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,26 +238,26 @@ 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);
|
||||
return getSSLSettingsForStore(resourcePathToStore, password, false, true, true);
|
||||
}
|
||||
|
||||
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled,
|
||||
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean useGeneratedSSLConfig,
|
||||
boolean hostnameVerificationEnabled, boolean transportClient) {
|
||||
Path store = resolveResourcePath(resourcePathToStore);
|
||||
|
||||
Settings.Builder builder = Settings.builder().put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
|
||||
if (transportClient == false) {
|
||||
builder.put("xpack.security.http.ssl.enabled", false);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled) {
|
||||
builder.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
if (useGeneratedSSLConfig == false) {
|
||||
builder.put("xpack.ssl.keystore.path", store)
|
||||
.put("xpack.ssl.keystore.password", password)
|
||||
.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
.put("xpack.ssl.keystore.password", password);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled && randomBoolean()) {
|
||||
if (useGeneratedSSLConfig == false && randomBoolean()) {
|
||||
builder.put("xpack.ssl.truststore.path", store)
|
||||
.put("xpack.ssl.truststore.password", password);
|
||||
}
|
||||
|
@ -265,20 +265,19 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
}
|
||||
|
||||
private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, String certificatePath,
|
||||
List<String> trustedCertificates, boolean sslTransportEnabled,
|
||||
List<String> trustedCertificates, boolean useGeneratedSSLConfig,
|
||||
boolean hostnameVerificationEnabled, boolean transportClient) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslTransportEnabled);
|
||||
|
||||
if (transportClient == false) {
|
||||
builder.put("xpack.security.http.ssl.enabled", false);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled) {
|
||||
builder.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
if (useGeneratedSSLConfig == false) {
|
||||
builder.put("xpack.ssl.key", resolveResourcePath(keyPath))
|
||||
.put("xpack.ssl.key_passphrase", password)
|
||||
.put("xpack.ssl.certificate", resolveResourcePath(certificatePath))
|
||||
.put("xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate");
|
||||
.put("xpack.ssl.certificate", resolveResourcePath(certificatePath));
|
||||
|
||||
if (trustedCertificates.isEmpty() == false) {
|
||||
builder.put("xpack.ssl.certificate_authorities",
|
||||
|
|
|
@ -18,7 +18,6 @@ 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;
|
||||
import java.util.List;
|
||||
|
@ -32,7 +31,7 @@ public class SettingsFilterTests extends ESTestCase {
|
|||
private Settings.Builder configuredSettingsBuilder = Settings.builder();
|
||||
private Map<String, Matcher> settingsMatcherMap = new HashMap<>();
|
||||
|
||||
public void testFiltering() throws IOException {
|
||||
public void testFiltering() throws Exception {
|
||||
configureUnfilteredSetting("xpack.security.authc.realms.file.type", "file");
|
||||
|
||||
// ldap realm filtering
|
||||
|
|
|
@ -5,17 +5,24 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack;
|
||||
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.xpack.support.clock.ClockMock;
|
||||
import org.elasticsearch.xpack.watcher.test.TimeWarpedWatcher;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.time.Clock;
|
||||
|
||||
public class TimeWarpedXPackPlugin extends XPackPlugin {
|
||||
private final ClockMock clock = new ClockMock();
|
||||
|
||||
public TimeWarpedXPackPlugin(Settings settings) throws IOException {
|
||||
public TimeWarpedXPackPlugin(Settings settings) throws IOException, CertificateException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, KeyStoreException, DestroyFailedException, OperatorCreationException {
|
||||
super(settings);
|
||||
watcher = new TimeWarpedWatcher(settings);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
|||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
|
|
@ -104,8 +104,6 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
|
||||
final boolean httpSSLEnabled = randomBoolean();
|
||||
settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled);
|
||||
final boolean transportSSLEnabled = randomBoolean();
|
||||
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())
|
||||
|
@ -171,9 +169,8 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
assertThat(source.getValue("realms"), is(notNullValue()));
|
||||
}
|
||||
|
||||
// check SSL
|
||||
// check http SSL
|
||||
assertThat(source.getValue("ssl.http.enabled"), is(httpSSLEnabled));
|
||||
assertThat(source.getValue("ssl.transport.enabled"), is(transportSSLEnabled));
|
||||
|
||||
// auditing
|
||||
assertThat(source.getValue("audit.enabled"), is(auditingEnabled));
|
||||
|
|
|
@ -58,14 +58,14 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
|
||||
private static final String SECOND_CLUSTER_NODE_PREFIX = "node_cluster2_";
|
||||
private static InternalTestCluster cluster2;
|
||||
private static boolean useSSL;
|
||||
private static boolean useGeneratedSSL;
|
||||
|
||||
private Node tribeNode;
|
||||
private Client tribeClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupSSL() {
|
||||
useSSL = randomBoolean();
|
||||
useGeneratedSSL = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,7 +73,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
super.setUp();
|
||||
if (cluster2 == null) {
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useSSL, systemKey(), createTempDir(), Scope.SUITE);
|
||||
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, systemKey(), createTempDir(), Scope.SUITE);
|
||||
cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, true, 1, 2,
|
||||
UUIDs.randomBase64UUID(random()), cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(),
|
||||
getClientWrapper());
|
||||
|
@ -82,6 +82,11 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return useGeneratedSSL;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownSecondCluster() {
|
||||
if (cluster2 != null) {
|
||||
|
@ -123,18 +128,14 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return useSSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ignoreExternalCluster() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException {
|
||||
SecuritySettingsSource cluster2SettingsSource = new SecuritySettingsSource(1, useSSL, systemKey(), createTempDir(), Scope.TEST);
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(1, useGeneratedSSL, systemKey(), createTempDir(), Scope.TEST);
|
||||
Map<String,String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap());
|
||||
asMap.remove(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey());
|
||||
Settings.Builder tribe1Defaults = Settings.builder();
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.elasticsearch.transport.MockTcpTransportPlugin;
|
|||
import org.elasticsearch.transport.TransportInfo;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail.Message;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
|
||||
|
@ -56,6 +57,7 @@ import org.junit.BeforeClass;
|
|||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -132,10 +134,11 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
// Setup a second test cluster with randomization for number of nodes, security enabled, and SSL
|
||||
final int numNodes = randomIntBetween(1, 2);
|
||||
final boolean useSecurity = randomBoolean();
|
||||
final boolean useSSL = useSecurity && randomBoolean();
|
||||
logger.info("--> remote indexing enabled. security enabled: [{}], SSL enabled: [{}], nodes: [{}]", useSecurity, useSSL, numNodes);
|
||||
final boolean useGeneratedSSL = useSecurity && randomBoolean();
|
||||
logger.info("--> remote indexing enabled. security enabled: [{}], SSL enabled: [{}], nodes: [{}]", useSecurity, useGeneratedSSL,
|
||||
numNodes);
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(numNodes, useSSL, systemKey(), createTempDir(), Scope.SUITE) {
|
||||
new SecuritySettingsSource(numNodes, useGeneratedSSL, systemKey(), createTempDir(), Scope.SUITE) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
|
@ -146,6 +149,21 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings transportClientSettings() {
|
||||
if (useSecurity) {
|
||||
return super.transportClientSettings();
|
||||
} else {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(XPackSettings.SECURITY_ENABLED.getKey(), false)
|
||||
.put(super.transportClientSettings());
|
||||
if (builder.get(NetworkModule.TRANSPORT_TYPE_KEY) == null) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -163,17 +181,19 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
TransportAddress inet = info.address().publishAddress();
|
||||
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(XPackSettings.SECURITY_ENABLED.getKey(), useSecurity)
|
||||
.put("xpack.security.audit.index.client." + XPackSettings.SECURITY_ENABLED.getKey(), useSecurity)
|
||||
.put(remoteSettings(NetworkAddress.format(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.DEFAULT_USER_NAME + ":" +
|
||||
SecuritySettingsSource.DEFAULT_PASSWORD);
|
||||
|
||||
if (useSSL) {
|
||||
if (useGeneratedSSL == false) {
|
||||
for (Map.Entry<String, String> entry : cluster2SettingsSource.getClientSSLSettings().getAsMap().entrySet()) {
|
||||
builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
builder.put("xpack.security.audit.index.client.xpack.ssl.client_authentication", "none");
|
||||
}
|
||||
if (useSecurity == false && builder.get(NetworkModule.TRANSPORT_TYPE_KEY) == null) {
|
||||
builder.put("xpack.security.audit.index.client." + NetworkModule.TRANSPORT_TYPE_KEY,
|
||||
MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME);
|
||||
}
|
||||
remoteSettings = builder.build();
|
||||
}
|
||||
|
@ -283,6 +303,11 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
enqueuedMessage.set(message);
|
||||
super.enqueue(message, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Class<? extends Plugin>> remoteTransportClientPlugins() {
|
||||
return Arrays.asList(XPackPlugin.class, MockTcpTransportPlugin.class);
|
||||
}
|
||||
};
|
||||
auditor.start(true);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.stream.StreamSupport;
|
|||
|
||||
import static org.elasticsearch.test.InternalTestCluster.clusterName;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
* This test checks to ensure that the IndexAuditTrail starts properly when indexing to a remote cluster. The cluster
|
||||
|
@ -50,13 +49,13 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase {
|
|||
|
||||
private InternalTestCluster remoteCluster;
|
||||
|
||||
private final boolean useSSL = randomBoolean();
|
||||
private final boolean useGeneratedSSL = randomBoolean();
|
||||
private final boolean localAudit = randomBoolean();
|
||||
private final String outputs = randomFrom("index", "logfile", "index,logfile");
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return useSSL;
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return useGeneratedSSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,7 +89,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase {
|
|||
// Setup a second test cluster with a single node, security enabled, and SSL
|
||||
final int numNodes = 1;
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(numNodes, useSSL, systemKey(), createTempDir(), Scope.TEST) {
|
||||
new SecuritySettingsSource(numNodes, useGeneratedSSL, systemKey(), createTempDir(), Scope.TEST) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
|
|
|
@ -48,11 +48,6 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String configRoles() {
|
||||
return ROLES + super.configRoles();
|
||||
|
@ -72,6 +67,11 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
+ "transport_client:" + TRANSPORT_CLIENT_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void testUserImpersonation() throws Exception {
|
||||
try (TransportClient client = getTransportClient(Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
|
||||
|
@ -222,7 +222,6 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(extraSettings)
|
||||
.put("cluster.name", clusterName)
|
||||
.put("xpack.security.transport.ssl.enabled", false)
|
||||
.build();
|
||||
|
||||
return new TestXPackTransportClient(settings)
|
||||
|
|
|
@ -49,8 +49,9 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return useSSL;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
// don't use autogenerated when we expect a different cert
|
||||
return useSSL == false;
|
||||
}
|
||||
|
||||
private Environment nodeEnvironment() throws Exception {
|
||||
|
|
|
@ -55,7 +55,9 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
assertThat(response.getClusterName(), is(cluster().getClusterName()));
|
||||
}
|
||||
|
||||
ChangePasswordResponse response = securityClient().prepareChangePassword(username, newPassword).get();
|
||||
ChangePasswordResponse response = securityClient()
|
||||
.prepareChangePassword(username, Arrays.copyOf(newPassword, newPassword.length))
|
||||
.get();
|
||||
assertThat(response, notNullValue());
|
||||
|
||||
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
|
||||
|
|
|
@ -30,7 +30,7 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase {
|
|||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
useGlobalSSL = randomBoolean();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Path truststore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
/*
|
||||
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
|
||||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
|
@ -38,19 +38,19 @@ public class AbstractActiveDirectoryIntegTests extends ESTestCase {
|
|||
*/
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.truststore.path", truststore)
|
||||
.put("xpack.ssl.truststore.password", "changeit");
|
||||
|
||||
// fake realm to load config with certificate verification mode
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
} else {
|
||||
// fake realms so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
}
|
||||
|
|
|
@ -43,24 +43,24 @@ public abstract class GroupsResolverTestCase extends ESTestCase {
|
|||
|
||||
@Before
|
||||
public void setUpLdapConnection() throws Exception {
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Path truststore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
boolean useGlobalSSL = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.truststore.path", truststore)
|
||||
.put("xpack.ssl.truststore.password", "changeit");
|
||||
|
||||
// fake realm to load config with certificate verification mode
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
} else {
|
||||
// fake realms so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.keystore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
}
|
||||
Settings settings = builder.build();
|
||||
|
@ -78,8 +78,8 @@ public abstract class GroupsResolverTestCase extends ESTestCase {
|
|||
if (useGlobalSSL) {
|
||||
connectionSettings = Settings.EMPTY;
|
||||
} else {
|
||||
connectionSettings = Settings.builder().put("keystore.path", keystore)
|
||||
.put("keystore.password", "changeit").build();
|
||||
connectionSettings = Settings.builder().put("truststore.path", truststore)
|
||||
.put("truststore.password", "changeit").build();
|
||||
}
|
||||
ldapConnection = LdapUtils.privilegedConnect(() -> new LDAPConnection(sslService.sslSocketFactory(connectionSettings), options,
|
||||
ldapurl.getHost(), ldapurl.getPort(), bindDN(), bindPassword()));
|
||||
|
|
|
@ -37,7 +37,7 @@ public class LdapSessionFactoryTests extends LdapTestCase {
|
|||
private SSLService sslService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
public void setup() throws Exception {
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
sslService = new SSLService(globalSettings, new Environment(globalSettings));
|
||||
}
|
||||
|
|
|
@ -57,8 +57,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
*/
|
||||
globalSettings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit")
|
||||
.put("xpack.ssl.truststore.path", keystore)
|
||||
.put("xpack.ssl.truststore.password", "changeit")
|
||||
.build();
|
||||
sslService = new SSLService(globalSettings, env);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class OpenLdapTests extends ESTestCase {
|
|||
|
||||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Path truststore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
/*
|
||||
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
|
||||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
|
@ -53,19 +53,19 @@ public class OpenLdapTests extends ESTestCase {
|
|||
useGlobalSSL = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.ssl.keystore.path", keystore)
|
||||
.put("xpack.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.ssl.truststore.path", truststore)
|
||||
.put("xpack.ssl.truststore.password", "changeit");
|
||||
|
||||
// fake realm to load config with certificate verification mode
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.keystore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
} else {
|
||||
// fake realms so ssl will get loaded
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.foo.ssl.verification_mode", VerificationMode.FULL);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", keystore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.path", truststore);
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.truststore.password", "changeit");
|
||||
builder.put("xpack.security.authc.realms.bar.ssl.verification_mode", VerificationMode.CERTIFICATE);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import static org.hamcrest.Matchers.is;
|
|||
|
||||
public class SessionFactoryTests extends ESTestCase {
|
||||
|
||||
public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultSettings() {
|
||||
public void testConnectionFactoryReturnsCorrectLDAPConnectionOptionsWithDefaultSettings() throws Exception {
|
||||
final Environment environment = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
RealmConfig realmConfig = new RealmConfig("conn settings", Settings.EMPTY, environment.settings(), environment);
|
||||
LDAPConnectionOptions options = SessionFactory.connectionOptions(realmConfig, new SSLService(environment.settings(), environment),
|
||||
|
@ -37,7 +37,7 @@ public class SessionFactoryTests extends ESTestCase {
|
|||
assertThat(options.getSSLSocketVerifier(), is(instanceOf(HostNameSSLSocketVerifier.class)));
|
||||
}
|
||||
|
||||
public void testConnectionFactoryReturnsCorrectLDAPConnectionOptions() {
|
||||
public void testConnectionFactoryReturnsCorrectLDAPConnectionOptions() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(SessionFactory.TIMEOUT_TCP_CONNECTION_SETTING, "10ms")
|
||||
.put(SessionFactory.HOSTNAME_VERIFICATION_SETTING, "false")
|
||||
|
|
|
@ -69,8 +69,8 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testTransportClientCanAuthenticateViaPki() {
|
||||
|
|
|
@ -10,15 +10,10 @@ import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
|
|||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.TestXPackTransportClient;
|
||||
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.ssl.SSLClientAuth;
|
||||
|
@ -27,15 +22,11 @@ import org.junit.BeforeClass;
|
|||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD;
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_USER_NAME;
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
||||
|
@ -71,8 +62,8 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testRestClientWithoutClientCertificate() throws Exception {
|
||||
|
@ -93,26 +84,6 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testTransportClientWithoutClientCertificate() {
|
||||
Transport transport = internalCluster().getDataNodeInstance(Transport.class);
|
||||
int port = randomFrom(transport.profileBoundAddresses().get("want_client_auth").boundAddresses()).address().getPort();
|
||||
|
||||
Settings sslSettingsForStore = getSSLSettingsForStore
|
||||
("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks", "truststore-testnode-only");
|
||||
Settings settings = Settings.builder()
|
||||
.put(sslSettingsForStore)
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED)
|
||||
.build();
|
||||
|
||||
|
||||
try (TransportClient client = new TestXPackTransportClient(settings)) {
|
||||
client.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), port));
|
||||
assertGreenClusterState(client);
|
||||
}
|
||||
}
|
||||
|
||||
private SSLContext getSSLContext() throws Exception {
|
||||
SSLContext sc = SSLContext.getInstance("TLSv1.2");
|
||||
Path truststore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks");
|
||||
|
|
|
@ -44,13 +44,12 @@ public class PkiRealmTests extends ESTestCase {
|
|||
private SSLService sslService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
public void setup() throws Exception {
|
||||
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));
|
||||
}
|
||||
|
@ -217,7 +216,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
assertThat(e.getMessage(), containsString("has SSL with client authentication enabled"));
|
||||
}
|
||||
|
||||
public void testHttpClientAuthOnly() {
|
||||
public void testHttpClientAuthOnly() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(globalSettings)
|
||||
.put("xpack.ssl.client_authentication", "none")
|
||||
|
@ -228,18 +227,6 @@ public class PkiRealmTests extends ESTestCase {
|
|||
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");
|
||||
|
|
|
@ -42,9 +42,10 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
randomClientPort = randomIntBetween(49000, 65500); // ephemeral port
|
||||
}
|
||||
|
||||
// don't use it here to simplify the settings we need
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,11 +61,9 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
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("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED);
|
||||
}
|
||||
settingsBuilder.put("transport.profiles.client.xpack.security.truststore.path", store) // settings for client truststore
|
||||
.put("transport.profiles.client.xpack.security.truststore.password", "testnode")
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED);
|
||||
|
||||
return settingsBuilder
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
|
@ -94,7 +93,6 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
|
|||
.put("network.host", "localhost")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put("discovery.zen.ping.unicast.hosts", unicastHost)
|
||||
.put("xpack.security.transport.ssl.enabled", sslTransportEnabled())
|
||||
.put("xpack.security.audit.enabled", false)
|
||||
.put("path.home", home)
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
|
||||
|
@ -123,7 +121,6 @@ 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("xpack.security.transport.ssl.enabled", sslTransportEnabled())
|
||||
.put("xpack.security.audit.enabled", false)
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
|
||||
.put("discovery.initial_state_timeout", "0s")
|
||||
|
|
|
@ -88,8 +88,8 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return true;
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,7 +97,6 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Settings defaultSettings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false))
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("transport.host", hostName);
|
||||
String confPath = Environment.PATH_CONF_SETTING.get(defaultSettings);
|
||||
Path path = PathUtils.get(confPath).resolve("keystore.jks");
|
||||
|
@ -126,8 +125,7 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
public Settings transportClientSettings() {
|
||||
Settings defaultSettings = super.transportClientSettings();
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false))
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true);
|
||||
.put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false));
|
||||
Path path = createTempDir().resolve("keystore.jks");
|
||||
try (OutputStream os = Files.newOutputStream(path)) {
|
||||
keystore.store(os, "changeme".toCharArray());
|
||||
|
|
|
@ -22,19 +22,15 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase {
|
|||
Path keystore;
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false));
|
||||
settings = builder.build();
|
||||
|
||||
// The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP
|
||||
|
|
|
@ -17,7 +17,6 @@ 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.XPackSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.junit.Before;
|
||||
|
@ -26,10 +25,8 @@ import javax.net.ssl.SSLEngine;
|
|||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class SecurityNetty4TransportTests extends ESTestCase {
|
||||
|
@ -49,14 +46,13 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
sslService = new SSLService(settings, env);
|
||||
}
|
||||
|
||||
private SecurityNetty4Transport createTransport(boolean sslEnabled) {
|
||||
return createTransport(sslEnabled, Settings.EMPTY);
|
||||
private SecurityNetty4Transport createTransport() {
|
||||
return createTransport(Settings.EMPTY);
|
||||
}
|
||||
|
||||
private SecurityNetty4Transport createTransport(boolean sslEnabled, Settings additionalSettings) {
|
||||
private SecurityNetty4Transport createTransport(Settings additionalSettings) {
|
||||
final Settings settings =
|
||||
Settings.builder()
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslEnabled)
|
||||
.put(additionalSettings)
|
||||
.build();
|
||||
return new SecurityNetty4Transport(
|
||||
|
@ -70,26 +66,8 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
sslService);
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeDisabledByProfile() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl.enabled", false).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class), nullValue());
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeEnabledByProfile() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport(false);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl.enabled", true).build());
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
assertThat(ch.pipeline().get(SslHandler.class), notNullValue());
|
||||
}
|
||||
|
||||
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
SecurityNetty4Transport transport = createTransport();
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -97,7 +75,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
SecurityNetty4Transport transport = createTransport(true);
|
||||
SecurityNetty4Transport transport = createTransport();
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -112,7 +90,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -127,7 +105,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -142,7 +120,7 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
.put("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = createTransport(true, settings);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
@ -154,11 +132,10 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
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);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
|
@ -171,11 +148,10 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
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);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
|
@ -188,11 +164,10 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.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);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
final ChannelHandler handler = transport.getServerChannelInitializer("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
|
@ -201,56 +176,20 @@ public class SecurityNetty4TransportTests extends ESTestCase {
|
|||
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = new SecurityNetty4Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService);
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY));
|
||||
assertThat(e.getMessage(), containsString("key must be provided"));
|
||||
}
|
||||
|
||||
public void testNoExceptionWhenConfiguredWithoutSslKeySSLDisabled() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty4Transport transport = new SecurityNetty4Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), null, sslService);
|
||||
assertNotNull(transport.getServerChannelInitializer(randomAsciiOfLength(6), Settings.EMPTY));
|
||||
}
|
||||
|
||||
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("xpack.ssl.truststore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.ssl.truststore.password", "truststore-testnode-only")
|
||||
.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);
|
||||
SecurityNetty4Transport transport = createTransport(settings);
|
||||
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
final ChannelHandler handler = transport.getServerChannelInitializer("default", Settings.EMPTY);
|
||||
final EmbeddedChannel ch = new EmbeddedChannel(handler);
|
||||
|
|
|
@ -26,8 +26,8 @@ import static org.hamcrest.Matchers.containsString;
|
|||
public class SslHostnameVerificationTests extends SecurityIntegTestCase {
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,8 +52,8 @@ public class SslIntegrationTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no SSL exception as this is the exception is returned when connecting
|
||||
|
|
|
@ -30,13 +30,11 @@ import static org.hamcrest.Matchers.containsString;
|
|||
public class SslMultiPortTests extends SecurityIntegTestCase {
|
||||
|
||||
private static int randomClientPort;
|
||||
private static int randomNonSslPort;
|
||||
private static int randomNoClientAuthPort;
|
||||
|
||||
@BeforeClass
|
||||
public static void getRandomPort() {
|
||||
randomClientPort = randomIntBetween(49000, 65500); // ephemeral port
|
||||
randomNonSslPort = randomIntBetween(49000, 65500);
|
||||
randomNoClientAuthPort = randomIntBetween(49000, 65500);
|
||||
}
|
||||
|
||||
|
@ -46,13 +44,11 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
* <li>default: testnode keystore. Requires client auth</li>
|
||||
* <li>client: testnode-client-profile keystore that only trusts the testclient cert. Requires client auth</li>
|
||||
* <li>no_client_auth: testnode keystore. Does not require client auth</li>
|
||||
* <li>no_ssl: plaintext transport profile</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
String randomClientPortRange = randomClientPort + "-" + (randomClientPort+100);
|
||||
String randomNonSslPortRange = randomNonSslPort + "-" + (randomNonSslPort+100);
|
||||
String randomNoClientAuthPortRange = randomNoClientAuthPort + "-" + (randomNoClientAuthPort+100);
|
||||
|
||||
Path store;
|
||||
|
@ -71,9 +67,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
.put("transport.profiles.client.bind_host", "localhost")
|
||||
.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("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_authentication", SSLClientAuth.NONE)
|
||||
|
@ -81,23 +74,13 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private TransportClient createTransportClient(Settings additionalSettings) {
|
||||
Settings clientSettings = transportClientSettings();
|
||||
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.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
clientSettings = builder.build();
|
||||
}
|
||||
|
||||
Settings settings = Settings.builder().put(clientSettings)
|
||||
Settings settings = Settings.builder()
|
||||
.put(transportClientSettings().filter(s -> s.startsWith("xpack.ssl") == false))
|
||||
.put("node.name", "programmatic_transport_client")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(additionalSettings)
|
||||
|
@ -121,7 +104,11 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
* disabling the client auth requirement
|
||||
*/
|
||||
public void testThatStandardTransportClientCanConnectToNoClientAuthProfile() throws Exception {
|
||||
try(TransportClient transportClient = createTransportClient(Settings.EMPTY)) {
|
||||
try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder()
|
||||
.put(transportClientSettings())
|
||||
.put("node.name", "programmatic_transport_client")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.build())) {
|
||||
transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(),
|
||||
getProfilePort("no_client_auth")));
|
||||
assertGreenClusterState(transportClient);
|
||||
|
@ -145,21 +132,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with the same settings as the internal cluster transport client to test connection to the
|
||||
* no_ssl profile. The internal transport client is not used here since we are connecting to a different
|
||||
* profile. The no_ssl profile is plain text and the standard transport client uses SSL, so a connection will never work
|
||||
*/
|
||||
public void testThatStandardTransportClientCannotConnectToNoSslProfile() throws Exception {
|
||||
try (TransportClient transportClient = createTransportClient(Settings.EMPTY)) {
|
||||
transportClient.addTransportAddress(new TransportAddress(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#-"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with a custom keystore; this keystore testclient-client-profile.jks trusts the testnode
|
||||
* certificate and had its own self signed certificate. This test connects to the client profile, which is only
|
||||
|
@ -209,38 +181,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with a custom keystore; this keystore testclient-client-profile.jks trusts the testnode
|
||||
* certificate and had its own self signed certificate. This test connects to the no_ssl profile, which does not
|
||||
* use SSL so the connection will never work
|
||||
*/
|
||||
public void testThatProfileTransportClientCannotConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = getSSLSettingsForStore(
|
||||
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile");
|
||||
try (TransportClient transportClient = createTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
|
||||
transportClient.admin().cluster().prepareHealth().get();
|
||||
fail("Expected NoNodeAvailableException");
|
||||
} catch (NoNodeAvailableException e) {
|
||||
assertThat(e.getMessage(), containsString("None of the configured nodes are available: [{#transport#-"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with SSL disabled. This test connects to the no_ssl profile, which should always succeed
|
||||
*/
|
||||
public void testThatTransportClientCanConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("xpack.security.transport.ssl.enabled", false)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.build();
|
||||
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_ssl")));
|
||||
assertGreenClusterState(transportClient);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with SSL disabled. This test connects to the default profile, which should always fail
|
||||
* as a non-ssl transport client cannot connect to a ssl profile
|
||||
|
@ -305,7 +245,6 @@ 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("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.ssl.truststore.password", "truststore-testnode-only")
|
||||
|
@ -365,29 +304,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with a custom truststore; this truststore truststore-testnode-only only trusts the testnode
|
||||
* certificate and contains no other certification. This test connects to the no_ssl profile, which does not use
|
||||
* SSL so the connection should never succeed
|
||||
*/
|
||||
public void testThatTransportClientWithOnlyTruststoreCannotConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.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.ssl.truststore.password", "truststore-testnode-only")
|
||||
.build();
|
||||
try (TransportClient transportClient = new TestXPackTransportClient(settings)) {
|
||||
transportClient.addTransportAddress(new TransportAddress(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#-"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a transport client with the default JDK truststore; this truststore only trusts the known good public
|
||||
* certificate authorities. This test connects to the default profile, which uses a self-signed certificate that
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.transport.ssl;
|
||||
|
||||
import org.elasticsearch.action.DocWriteResponse.Result;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
|
||||
/**
|
||||
* An extremely simple test that shows SSL will work with a cipher that does not perform encryption
|
||||
*/
|
||||
public class SslNullCipherTests extends SecurityIntegTestCase {
|
||||
|
||||
@Override
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(settings.filter((s) -> s.startsWith("xpack.ssl") == false));
|
||||
builder.put("xpack.security.transport.ssl.cipher_suites", "TLS_RSA_WITH_NULL_SHA256");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings transportClientSettings() {
|
||||
Settings settings = super.transportClientSettings();
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(settings.filter((s) -> s.startsWith("xpack.ssl") == false));
|
||||
|
||||
builder.put("xpack.security.transport.ssl.cipher_suites", "TLS_RSA_WITH_NULL_SHA256");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void testClusterIsFormed() {
|
||||
ensureGreen();
|
||||
Client client = internalCluster().transportClient();
|
||||
IndexResponse response = client.prepareIndex("index", "type").setSource("foo", "bar").get();
|
||||
assertEquals(Result.CREATED, response.getResult());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.settings.Settings;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class GeneratedKeyConfigTests extends ESTestCase {
|
||||
|
||||
public void testGenerating() throws Exception {
|
||||
Settings settings = Settings.builder().put(Node.NODE_NAME_SETTING.getKey(), randomAsciiOfLengthBetween(1, 8)).build();
|
||||
GeneratedKeyConfig keyConfig = new GeneratedKeyConfig(settings);
|
||||
assertThat(keyConfig.filesToMonitor(null), is(empty()));
|
||||
X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(null);
|
||||
assertNotNull(keyManager);
|
||||
assertNotNull(keyConfig.createTrustManager(null));
|
||||
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertEquals(1, aliases.length);
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(aliases[0]);
|
||||
assertNotNull(privateKey);
|
||||
assertThat(privateKey, instanceOf(RSAPrivateKey.class));
|
||||
X509Certificate[] certificates = keyManager.getCertificateChain(aliases[0]);
|
||||
assertEquals(2, certificates.length);
|
||||
assertEquals(GeneratedKeyConfig.readCACert(), certificates[1]);
|
||||
|
||||
X509Certificate generatedCertificate = certificates[0];
|
||||
assertEquals("CN=" + Node.NODE_NAME_SETTING.get(settings), generatedCertificate.getSubjectX500Principal().getName());
|
||||
assertEquals(certificates[1].getSubjectX500Principal(), generatedCertificate.getIssuerX500Principal());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
public class SSLBootstrapCheckTests extends ESTestCase {
|
||||
|
||||
public void testSSLBootstrapCheckWithNoKey() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, null);
|
||||
SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(sslService, Settings.EMPTY, null);
|
||||
assertTrue(bootstrapCheck.check());
|
||||
}
|
||||
|
||||
public void testSSLBootstrapCheckWithKey() throws Exception {
|
||||
final String keyPrefix = randomBoolean() ? "security.transport." : "";
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack." + keyPrefix + "ssl.key",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem"))
|
||||
.put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient")
|
||||
.put("xpack." + keyPrefix + "ssl.certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"))
|
||||
.build();
|
||||
final Environment env = randomBoolean() ? new Environment(settings) : null;
|
||||
SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env);
|
||||
assertFalse(bootstrapCheck.check());
|
||||
}
|
||||
|
||||
public void testSSLBootstrapCheckWithDefaultCABeingTrusted() throws Exception {
|
||||
final String keyPrefix = randomBoolean() ? "security.transport." : "";
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack." + keyPrefix + "ssl.key",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem"))
|
||||
.put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient")
|
||||
.put("xpack." + keyPrefix + "ssl.certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"))
|
||||
.putArray("xpack." + keyPrefix + "ssl.certificate_authorities",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt").toString(),
|
||||
getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString())
|
||||
.build();
|
||||
final Environment env = randomBoolean() ? new Environment(settings) : null;
|
||||
SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env);
|
||||
assertTrue(bootstrapCheck.check());
|
||||
|
||||
settings = Settings.builder().put(settings.filter((s) -> s.contains(".certificate_authorities")))
|
||||
.put("xpack.security.http.ssl.certificate_authorities",
|
||||
getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString())
|
||||
.build();
|
||||
bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env);
|
||||
assertTrue(bootstrapCheck.check());
|
||||
}
|
||||
|
||||
public void testSSLBootstrapCheckWithDefaultKeyBeingUsed() throws Exception {
|
||||
final String keyPrefix = randomBoolean() ? "security.transport." : "";
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack." + keyPrefix + "ssl.key",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem"))
|
||||
.put("xpack." + keyPrefix + "ssl.key_passphrase", "testclient")
|
||||
.put("xpack." + keyPrefix + "ssl.certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"))
|
||||
.put("xpack.security.http.ssl.key", getDataPath("/org/elasticsearch/xpack/ssl/private.pem").toString())
|
||||
.put("xpack.security.http.ssl.certificate", getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString())
|
||||
.build();
|
||||
final Environment env = randomBoolean() ? new Environment(settings) : null;
|
||||
SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env);
|
||||
assertTrue(bootstrapCheck.check());
|
||||
|
||||
settings = Settings.builder().put(settings.filter((s) -> s.contains(".http.ssl.")))
|
||||
.put("xpack.security.transport.profiles.foo.xpack.security.ssl.key",
|
||||
getDataPath("/org/elasticsearch/xpack/ssl/private.pem").toString())
|
||||
.put("xpack.security.transport.profiles.foo.xpack.security.ssl.certificate",
|
||||
getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString())
|
||||
.build();
|
||||
bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), settings, env);
|
||||
assertTrue(bootstrapCheck.check());
|
||||
}
|
||||
}
|
|
@ -55,8 +55,8 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testThatHttpFailsWithoutSslClientAuth() throws IOException {
|
||||
|
@ -90,7 +90,6 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.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")
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.junit.Before;
|
|||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
@ -34,8 +35,9 @@ import java.security.KeyStore;
|
|||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -81,21 +83,19 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
.build();
|
||||
final Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
|
||||
final BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPreChecks = (keyManager, config) -> {
|
||||
final BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPreChecks = (keyManager, config) -> {
|
||||
// key manager checks
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("testnode"));
|
||||
return null;
|
||||
};
|
||||
|
||||
final SetOnce<Integer> trustedCount = new SetOnce<>();
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks = (trustManager, config) -> {
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks = (trustManager, config) -> {
|
||||
// trust manager checks
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
trustedCount.set(certificates.length);
|
||||
return null;
|
||||
};
|
||||
|
||||
final Runnable modifier = () -> {
|
||||
|
@ -103,6 +103,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
// modify it
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
final KeyPair keyPair = CertUtils.generateKeyPair(512);
|
||||
X509Certificate cert = CertUtils.generateSignedCertificate(new X500Principal("CN=testReloadingKeyStore"), null, keyPair,
|
||||
null, null, 365);
|
||||
keyStore.setKeyEntry("key", keyPair.getPrivate(), "testnode".toCharArray(), new X509Certificate[] { cert });
|
||||
Path updated = tempDir.resolve("updated.jks");
|
||||
try (OutputStream out = Files.newOutputStream(updated)) {
|
||||
keyStore.store(out, "testnode".toCharArray());
|
||||
|
@ -113,11 +117,16 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(5));
|
||||
return null;
|
||||
final BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPostChecks = (updatedKeyManager, config) -> {
|
||||
String[] aliases = updatedKeyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
};
|
||||
validateSSLConfigurationIsReloaded(settings, env, keyManagerPreChecks, trustManagerPreChecks, modifier, (k, c) -> null,
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(4));
|
||||
};
|
||||
validateSSLConfigurationIsReloaded(settings, env, keyManagerPreChecks, trustManagerPreChecks, modifier, keyManagerPostChecks,
|
||||
trustManagerPostChecks);
|
||||
}
|
||||
|
||||
|
@ -144,14 +153,13 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
|
||||
final SetOnce<PrivateKey> privateKey = new SetOnce<>();
|
||||
final BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPreChecks = (keyManager, config) -> {
|
||||
final BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPreChecks = (keyManager, config) -> {
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
privateKey.set(keyManager.getPrivateKey("key"));
|
||||
assertNotNull(privateKey.get());
|
||||
return null;
|
||||
};
|
||||
|
||||
final KeyPair keyPair = CertUtils.generateKeyPair(randomFrom(1024, 2048));
|
||||
|
@ -180,14 +188,13 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
final BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPostChecks = (keyManager, config) -> {
|
||||
final BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPostChecks = (keyManager, config) -> {
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
assertThat(keyManager.getPrivateKey(aliases[0]), not(equalTo(privateKey)));
|
||||
assertThat(keyManager.getPrivateKey(aliases[0]), is(equalTo(keyPair.getPrivate())));
|
||||
return null;
|
||||
};
|
||||
validateKeyConfigurationIsReloaded(settings, env, keyManagerPreChecks, modifier, keyManagerPostChecks);
|
||||
}
|
||||
|
@ -205,13 +212,15 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
final X500Principal expectedPrincipal = new X500Principal("CN=xpack public development ca");
|
||||
|
||||
final SetOnce<Integer> trustedCount = new SetOnce<>();
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks = (trustManager, config) -> {
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks = (trustManager, config) -> {
|
||||
// trust manager checks
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
trustedCount.set(certificates.length);
|
||||
return null;
|
||||
assertTrue(Arrays.stream(trustManager.getAcceptedIssuers())
|
||||
.anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal())));
|
||||
};
|
||||
|
||||
|
||||
|
@ -229,9 +238,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(5));
|
||||
return null;
|
||||
assertTrue(Arrays.stream(updatedTrustManager.getAcceptedIssuers())
|
||||
.anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal())));
|
||||
};
|
||||
|
||||
validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks);
|
||||
|
@ -250,13 +260,15 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
Environment env = randomBoolean() ? null : new Environment(settings);
|
||||
final X500Principal expectedPrincipal = new X500Principal("CN=xpack public development ca");
|
||||
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks = (trustManager, config) -> {
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks = (trustManager, config) -> {
|
||||
// trust manager checks
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(certificates.length, is(1));
|
||||
assertThat(certificates.length, is(2));
|
||||
assertThat(((X509Certificate)certificates[0]).getSubjectX500Principal().getName(), containsString("Test Client"));
|
||||
return null;
|
||||
assertTrue(Arrays.stream(trustManager.getAcceptedIssuers())
|
||||
.anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal())));
|
||||
};
|
||||
|
||||
final Runnable modifier = () -> {
|
||||
|
@ -270,11 +282,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
final BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
final BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks = (updatedTrustManager, config) -> {
|
||||
Certificate[] updatedCerts = updatedTrustManager.getAcceptedIssuers();
|
||||
assertThat(updatedCerts.length, is(1));
|
||||
assertThat(updatedCerts.length, is(2));
|
||||
assertThat(((X509Certificate)updatedCerts[0]).getSubjectX500Principal().getName(), containsString("Test Node"));
|
||||
return null;
|
||||
assertTrue(Arrays.stream(updatedTrustManager.getAcceptedIssuers())
|
||||
.anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal())));
|
||||
};
|
||||
|
||||
validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks);
|
||||
|
@ -425,9 +438,9 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
* Validates the trust configuration aspect of the SSLConfiguration is reloaded
|
||||
*/
|
||||
private void validateTrustConfigurationIsReloaded(Settings settings, Environment env,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks,
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks,
|
||||
Runnable modificationFunction,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks)
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks)
|
||||
throws Exception {
|
||||
validateSSLConfigurationIsReloaded(settings, env, false, true, null, trustManagerPreChecks, modificationFunction, null,
|
||||
trustManagerPostChecks);
|
||||
|
@ -437,10 +450,10 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
* Validates the trust configuration aspect of the SSLConfiguration is reloaded
|
||||
*/
|
||||
private void validateKeyConfigurationIsReloaded(Settings settings, Environment env,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPreChecks,
|
||||
Runnable modificationFunction,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPostChecks)
|
||||
throws Exception {
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPreChecks,
|
||||
Runnable modificationFunction,
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPostChecks)
|
||||
throws Exception {
|
||||
validateSSLConfigurationIsReloaded(settings, env, true, false, keyManagerPreChecks, null, modificationFunction,
|
||||
keyManagerPostChecks, null);
|
||||
}
|
||||
|
@ -449,22 +462,22 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
* Validates that both the key and trust configuration aspects of the SSLConfiguration are reloaded
|
||||
*/
|
||||
private void validateSSLConfigurationIsReloaded(Settings settings, Environment env,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPreChecks,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks,
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPreChecks,
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks,
|
||||
Runnable modificationFunction,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPostChecks,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks)
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPostChecks,
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks)
|
||||
throws Exception {
|
||||
validateSSLConfigurationIsReloaded(settings, env, true, true, keyManagerPreChecks, trustManagerPreChecks, modificationFunction,
|
||||
keyManagerPostChecks, trustManagerPostChecks);
|
||||
}
|
||||
|
||||
private void validateSSLConfigurationIsReloaded(Settings settings, Environment env, boolean checkKeys, boolean checkTrust,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPreChecks,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPreChecks,
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPreChecks,
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPreChecks,
|
||||
Runnable modificationFunction,
|
||||
BiFunction<X509ExtendedKeyManager, SSLConfiguration, Void> keyManagerPostChecks,
|
||||
BiFunction<X509ExtendedTrustManager, SSLConfiguration, Void> trustManagerPostChecks)
|
||||
BiConsumer<X509ExtendedKeyManager, SSLConfiguration> keyManagerPostChecks,
|
||||
BiConsumer<X509ExtendedTrustManager, SSLConfiguration> trustManagerPostChecks)
|
||||
throws Exception {
|
||||
|
||||
final CountDownLatch reloadLatch = new CountDownLatch(1);
|
||||
|
@ -494,12 +507,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
|
||||
// key manager checks
|
||||
if (checkKeys) {
|
||||
keyManagerPreChecks.apply(keyManager, config);
|
||||
keyManagerPreChecks.accept(keyManager, config);
|
||||
}
|
||||
|
||||
// trust manager checks
|
||||
if (checkTrust) {
|
||||
trustManagerPreChecks.apply(trustManager, config);
|
||||
trustManagerPreChecks.accept(trustManager, config);
|
||||
}
|
||||
|
||||
assertEquals("nothing should have called reload", 1, reloadLatch.getCount());
|
||||
|
@ -512,14 +525,14 @@ public class SSLConfigurationReloaderTests extends ESTestCase {
|
|||
if (checkKeys) {
|
||||
final X509ExtendedKeyManager updatedKeyManager = sslService.sslContextHolder(config).keyManager().getKeyManager();
|
||||
assertThat(updatedKeyManager, not(sameInstance(keyManager)));
|
||||
keyManagerPostChecks.apply(updatedKeyManager, config);
|
||||
keyManagerPostChecks.accept(updatedKeyManager, config);
|
||||
}
|
||||
|
||||
// check trust manager
|
||||
if (checkTrust) {
|
||||
final X509ExtendedTrustManager updatedTrustManager = sslService.sslContextHolder(config).trustManager().getTrustManager();
|
||||
assertThat(updatedTrustManager, not(sameInstance(trustManager)));
|
||||
trustManagerPostChecks.apply(updatedTrustManager, config);
|
||||
trustManagerPostChecks.accept(updatedTrustManager, config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ package org.elasticsearch.xpack.ssl;
|
|||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.ssl.DefaultJDKTrustConfig.CombiningTrustConfig;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.ssl.TrustConfig.CombiningTrustConfig;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
|
|
@ -42,7 +42,6 @@ import java.security.KeyStore;
|
|||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
@ -68,12 +67,8 @@ 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("xpack.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false));
|
||||
|
||||
builder.put("resource.reload.interval.high", "1s")
|
||||
.put(SecuritySettingsSource.getSSLSettingsForStore(
|
||||
|
@ -88,8 +83,8 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
protected boolean useGeneratedSSLConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testThatSSLConfigurationReloadsOnModification() throws Exception {
|
||||
|
|
|
@ -157,18 +157,9 @@ public class SSLServiceTests extends ESTestCase {
|
|||
assertThat(sslEngine, notNullValue());
|
||||
}
|
||||
|
||||
public void testCreateWithoutAnySettingsNotValidForServer() throws Exception {
|
||||
public void testCreateWithoutAnySettingsValidForServer() 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));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, true));
|
||||
}
|
||||
|
||||
public void testCreateWithKeystoreIsValidForServer() throws Exception {
|
||||
|
@ -177,7 +168,7 @@ public class SSLServiceTests extends ESTestCase {
|
|||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, Settings.EMPTY));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, false));
|
||||
}
|
||||
|
||||
public void testValidForServerWithFallback() throws Exception {
|
||||
|
@ -186,7 +177,8 @@ public class SSLServiceTests extends ESTestCase {
|
|||
.put("xpack.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
SSLService sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl.")));
|
||||
// transport is valid in default config
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, true));
|
||||
|
||||
settings = Settings.builder()
|
||||
.put("xpack.ssl.truststore.path", testnodeStore)
|
||||
|
@ -195,13 +187,13 @@ public class SSLServiceTests extends ESTestCase {
|
|||
.put("xpack.security.transport.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.ssl.")));
|
||||
assertFalse(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, false));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(
|
||||
settings.getByPrefix("xpack.security.transport.ssl."), settings.getByPrefix("xpack.ssl.")));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, settings.getByPrefix("xpack.security.transport.ssl.")));
|
||||
settings.getByPrefix("xpack.security.transport.ssl."), false));
|
||||
assertTrue(sslService.isConfigurationValidForServerUsage(Settings.EMPTY, true));
|
||||
}
|
||||
|
||||
public void testGetVerificationMode() {
|
||||
public void testGetVerificationMode() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertThat(sslService.getVerificationMode(Settings.EMPTY, Settings.EMPTY), is(XPackSettings.VERIFICATION_MODE_DEFAULT));
|
||||
|
||||
|
@ -220,7 +212,7 @@ public class SSLServiceTests extends ESTestCase {
|
|||
is(VerificationMode.CERTIFICATE));
|
||||
}
|
||||
|
||||
public void testIsSSLClientAuthEnabled() {
|
||||
public void testIsSSLClientAuthEnabled() throws Exception {
|
||||
SSLService sslService = new SSLService(Settings.EMPTY, env);
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY));
|
||||
assertTrue(sslService.isSSLClientAuthEnabled(Settings.EMPTY, Settings.EMPTY));
|
||||
|
@ -238,7 +230,7 @@ public class SSLServiceTests extends ESTestCase {
|
|||
settings.getByPrefix("xpack.security.transport.ssl.")));
|
||||
}
|
||||
|
||||
public void testThatHttpClientAuthDefaultsToNone() {
|
||||
public void testThatHttpClientAuthDefaultsToNone() throws Exception {
|
||||
final Settings globalSettings = Settings.builder()
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.ssl.client_authentication", SSLClientAuth.OPTIONAL.name())
|
||||
|
|
|
@ -5,17 +5,25 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.ssl;
|
||||
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
/**
|
||||
* Extending SSLService to make helper methods public to access in tests
|
||||
*/
|
||||
public class TestsSSLService extends SSLService {
|
||||
|
||||
public TestsSSLService(Settings settings, Environment environment) {
|
||||
public TestsSSLService(Settings settings, Environment environment) throws CertificateException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, IOException, DestroyFailedException, KeyStoreException, OperatorCreationException {
|
||||
super(settings, environment);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.watcher.test.bench;
|
||||
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
@ -24,7 +25,12 @@ import org.elasticsearch.xpack.watcher.trigger.ScheduleTriggerEngineMock;
|
|||
import org.elasticsearch.xpack.watcher.trigger.TriggerEngine;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleRegistry;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.time.Clock;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -201,7 +207,8 @@ public class WatcherExecutorServiceBenchmark {
|
|||
public static final class XPackBenchmarkPlugin extends XPackPlugin {
|
||||
|
||||
|
||||
public XPackBenchmarkPlugin(Settings settings) throws IOException {
|
||||
public XPackBenchmarkPlugin(Settings settings) throws IOException, CertificateException, UnrecoverableKeyException,
|
||||
NoSuchAlgorithmException, KeyStoreException, DestroyFailedException, OperatorCreationException {
|
||||
super(settings);
|
||||
watcher = new BenchmarkWatcher(settings);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
|
|||
return tmpFile.exists()
|
||||
}
|
||||
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
|
||||
task oldClusterTest(type: RestIntegTestTask) {
|
||||
mustRunAfter(precommit)
|
||||
cluster {
|
||||
|
@ -58,6 +60,10 @@ task oldClusterTest(type: RestIntegTestTask) {
|
|||
clusterName = 'rolling-upgrade'
|
||||
waitCondition = waitWithAuth
|
||||
setting 'logger.org.elasticsearch.xpack.security', 'TRACE'
|
||||
setting 'xpack.security.transport.ssl.enabled', 'true'
|
||||
setting 'xpack.ssl.keystore.path', 'testnode.jks'
|
||||
setting 'xpack.ssl.keystore.password', 'testnode'
|
||||
extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks')
|
||||
}
|
||||
systemProperty 'tests.rest.suite', 'old_cluster'
|
||||
}
|
||||
|
@ -71,6 +77,9 @@ task mixedClusterTest(type: RestIntegTestTask) {
|
|||
unicastTransportUri = { seedNode, node, ant -> oldClusterTest.nodes.get(0).transportUri() }
|
||||
dataDir = "${-> oldClusterTest.nodes[1].dataDir}"
|
||||
waitCondition = waitWithAuth
|
||||
setting 'xpack.ssl.keystore.path', 'testnode.jks'
|
||||
setting 'xpack.ssl.keystore.password', 'testnode'
|
||||
extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks')
|
||||
}
|
||||
systemProperty 'tests.rest.suite', 'mixed_cluster'
|
||||
finalizedBy 'oldClusterTest#node0.stop'
|
||||
|
@ -85,6 +94,9 @@ task upgradedClusterTest(type: RestIntegTestTask) {
|
|||
unicastTransportUri = { seedNode, node, ant -> mixedClusterTest.nodes.get(0).transportUri() }
|
||||
dataDir = "${-> oldClusterTest.nodes[0].dataDir}"
|
||||
waitCondition = waitWithAuth
|
||||
setting 'xpack.ssl.keystore.path', 'testnode.jks'
|
||||
setting 'xpack.ssl.keystore.password', 'testnode'
|
||||
extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks')
|
||||
}
|
||||
systemProperty 'tests.rest.suite', 'upgraded_cluster'
|
||||
// only need to kill the mixed cluster tests node here because we explicitly told it to not stop nodes upon completion
|
||||
|
@ -104,7 +116,6 @@ dependencies {
|
|||
}
|
||||
|
||||
// copy x-pack plugin info so it is on the classpath and security manager has the right permissions
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
task copyXPackRestSpec(type: Copy) {
|
||||
dependsOn(project.configurations.restSpec, 'processTestResources')
|
||||
from project(':x-pack:elasticsearch').sourceSets.test.resources
|
||||
|
@ -112,8 +123,15 @@ task copyXPackRestSpec(type: Copy) {
|
|||
into project.sourceSets.test.output.resourcesDir
|
||||
}
|
||||
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
task copyTestNodeKeystore(type: Copy) {
|
||||
dependsOn(copyXPackRestSpec)
|
||||
from project(':x-pack:elasticsearch')
|
||||
.file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks')
|
||||
into outputDir
|
||||
}
|
||||
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
dependsOn(copyTestNodeKeystore)
|
||||
from project(':x-pack:elasticsearch').file('src/main/plugin-metadata')
|
||||
from project(':x-pack:elasticsearch').tasks.pluginProperties
|
||||
into outputDir
|
||||
|
|
|
@ -171,10 +171,9 @@ integTest {
|
|||
setting 'xpack.monitoring.exporters._http.auth.username', 'monitoring_agent'
|
||||
setting 'xpack.monitoring.exporters._http.auth.password', 'changeme'
|
||||
|
||||
setting 'xpack.security.transport.ssl.enabled', 'true'
|
||||
setting 'xpack.security.http.ssl.enabled', 'true'
|
||||
setting 'xpack.ssl.keystore.path', nodeKeystore.name
|
||||
setting 'xpack.ssl.keystore.password', 'keypass'
|
||||
setting 'xpack.security.http.ssl.keystore.path', nodeKeystore.name
|
||||
setting 'xpack.security.http.ssl.keystore.password', 'keypass'
|
||||
|
||||
plugin ':x-pack:elasticsearch'
|
||||
|
||||
|
|
|
@ -5,27 +5,19 @@
|
|||
*/
|
||||
package org.elasticsearch.smoketest;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.network.NetworkAddress;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -47,7 +39,6 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|||
public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
||||
private static final String USER = "test_user";
|
||||
private static final String PASS = "changeme";
|
||||
private static final String KEYSTORE_PASS = "keypass";
|
||||
private static final String MONITORING_PATTERN = ".monitoring-*";
|
||||
|
||||
@Override
|
||||
|
@ -59,9 +50,6 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
|||
protected Settings externalClusterClientSettings() {
|
||||
return Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("xpack.ssl.keystore.path", clientKeyStore)
|
||||
.put("xpack.ssl.keystore.password", KEYSTORE_PASS)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4).build();
|
||||
}
|
||||
|
||||
|
@ -122,23 +110,4 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
|||
}
|
||||
return httpAddresses;
|
||||
}
|
||||
|
||||
static Path clientKeyStore;
|
||||
|
||||
@BeforeClass
|
||||
public static void loadKeyStore() {
|
||||
try {
|
||||
clientKeyStore = PathUtils.get(SmokeTestMonitoringWithSecurityIT.class.getResource("/test-client.jks").toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ElasticsearchException("exception while reading the store", e);
|
||||
}
|
||||
if (!Files.exists(clientKeyStore)) {
|
||||
throw new IllegalStateException("Keystore file [" + clientKeyStore + "] does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void clearClientKeyStore() {
|
||||
clientKeyStore = null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue