SSL/TLS: Added support for different certs per profile
In order to run on different certs per port, we needed to adapt the logic of starting up. Also different profiles can now be applied to the N2NAuthenticator, so that a different profile can allow/deny different hosts. In addition minor refactorings have been done * Group keystore/truststore settings instead of using underscores * Change to transport profile settings instead of using specific shield ones Documentation has been updated as well Closes elastic/elasticsearch#290 Original commit: elastic/x-pack-elasticsearch@ad1ab974ea
This commit is contained in:
parent
f2abfb35f9
commit
2b108203fb
|
@ -23,24 +23,29 @@ import java.util.Arrays;
|
|||
* get SSLEngines and SocketFactories.
|
||||
*/
|
||||
public class SSLService extends AbstractComponent {
|
||||
static final String[] DEFAULT_CIPHERS = new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
|
||||
|
||||
static final String[] DEFAULT_CIPHERS = new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"};
|
||||
public static final String SHIELD_TRANSPORT_SSL = "shield.transport.ssl";
|
||||
public static final String SHIELD_HTTP_SSL = "shield.http.ssl";
|
||||
public static final String SHIELD_AUTHC_LDAP_URL = "shield.authc.ldap.url";
|
||||
|
||||
private final TrustManagerFactory trustFactory;
|
||||
private final SSLContext sslContext;
|
||||
private final String[] ciphers;
|
||||
private final KeyManagerFactory keyManagerFactory;
|
||||
private final String sslProtocol;
|
||||
|
||||
@Inject
|
||||
public SSLService(Settings settings) {
|
||||
super(settings);
|
||||
|
||||
String keyStorePath = componentSettings.get("keystore", System.getProperty("javax.net.ssl.keyStore"));
|
||||
String keyStorePassword = componentSettings.get("keystore_password", System.getProperty("javax.net.ssl.keyStorePassword"));
|
||||
String keyStoreAlgorithm = componentSettings.get("keystore_algorithm", System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()));
|
||||
String keyStorePath = componentSettings.get("keystore.path", System.getProperty("javax.net.ssl.keyStore"));
|
||||
String keyStorePassword = componentSettings.get("keystore.password", System.getProperty("javax.net.ssl.keyStorePassword"));
|
||||
String keyStoreAlgorithm = componentSettings.get("keystore.algorithm", System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()));
|
||||
|
||||
String trustStorePath = componentSettings.get("truststore", System.getProperty("javax.net.ssl.trustStore"));
|
||||
String trustStorePassword = componentSettings.get("truststore_password", System.getProperty("javax.net.ssl.trustStorePassword"));
|
||||
String trustStoreAlgorithm = componentSettings.get("truststore_algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
|
||||
String trustStorePath = componentSettings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore"));
|
||||
String trustStorePassword = componentSettings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword"));
|
||||
String trustStoreAlgorithm = componentSettings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
|
||||
|
||||
if (trustStorePath == null) {
|
||||
//the keystore will also be the truststore
|
||||
|
@ -57,46 +62,14 @@ public class SSLService extends AbstractComponent {
|
|||
|
||||
this.ciphers = componentSettings.getAsArray("ciphers", DEFAULT_CIPHERS);
|
||||
//protocols supported: https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
|
||||
String sslProtocol = componentSettings.get("protocol", "TLS");
|
||||
this.sslProtocol = componentSettings.get("protocol", "TLS");
|
||||
|
||||
logger.debug("using keyStore[{}], keyAlgorithm[{}], trustStore[{}], truststoreAlgorithm[{}], ciphersuites[{}], TLS protocol[{}]",
|
||||
keyStorePath, keyStoreAlgorithm, trustStorePath, trustStoreAlgorithm, ciphers, sslProtocol);
|
||||
|
||||
final TrustManagerFactory trustFactory;
|
||||
try (FileInputStream in = new FileInputStream(trustStorePath)) {
|
||||
// Load TrustStore
|
||||
KeyStore trustStore = KeyStore.getInstance("jks");
|
||||
trustStore.load(in, trustStorePassword == null ? null : trustStorePassword.toCharArray());
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(trustStore);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("Failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
|
||||
KeyStore keyStore;
|
||||
KeyManagerFactory keyManagerFactory;
|
||||
try (FileInputStream in = new FileInputStream(keyStorePath)){
|
||||
// Load KeyStore
|
||||
keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(in, keyStorePassword.toCharArray());
|
||||
|
||||
// Initialize KeyManagerFactory
|
||||
keyManagerFactory = KeyManagerFactory.getInstance(keyStoreAlgorithm);
|
||||
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchSSLException("Failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
|
||||
// Initialize sslContext
|
||||
try {
|
||||
sslContext = SSLContext.getInstance(sslProtocol);
|
||||
sslContext.init(keyManagerFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchSSLException("Failed to initialize the SSLContext", e);
|
||||
}
|
||||
this.trustFactory = getTrustFactory(trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
this.keyManagerFactory = createKeyManagerFactory(keyStorePath, keyStorePassword, keyStoreAlgorithm);
|
||||
this.sslContext = createSslContext(trustFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,26 +83,86 @@ public class SSLService extends AbstractComponent {
|
|||
* This engine is configured with a trust manager and a keystore that should have only one private key.
|
||||
* Four possible usages for elasticsearch exist:
|
||||
* Node-to-Node outbound:
|
||||
* - sslEngine.setUseClientMode(true)
|
||||
* - sslEngine.setUseClientMode(true)
|
||||
* Node-to-Node inbound:
|
||||
* - sslEngine.setUseClientMode(false)
|
||||
* - sslEngine.setNeedClientAuth(true)
|
||||
* - sslEngine.setUseClientMode(false)
|
||||
* - sslEngine.setNeedClientAuth(true)
|
||||
* Client-to-Node:
|
||||
* - sslEngine.setUseClientMode(true)
|
||||
* - sslEngine.setUseClientMode(true)
|
||||
* Http Client-to-Node (inbound):
|
||||
* - sslEngine.setUserClientMode(false)
|
||||
* - sslEngine.setNeedClientAuth(false)
|
||||
* - sslEngine.setUserClientMode(false)
|
||||
* - sslEngine.setNeedClientAuth(false)
|
||||
*/
|
||||
public SSLEngine createSSLEngine() {
|
||||
return createSSLEngine(this.sslContext);
|
||||
}
|
||||
|
||||
public SSLEngine createSSLEngineWithTruststore(Settings settings) {
|
||||
String trustStore = settings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore"));
|
||||
String trustStorePassword = settings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword"));
|
||||
String trustStoreAlgorithm = settings.get("truststore.algorithm", System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
|
||||
|
||||
// no truststore or password, return regular ssl engine
|
||||
if (trustStore == null || trustStorePassword == null) {
|
||||
return createSSLEngine();
|
||||
}
|
||||
|
||||
TrustManagerFactory trustFactory = getTrustFactory(trustStore, trustStorePassword, trustStoreAlgorithm);
|
||||
SSLContext customTruststoreSSLContext = createSslContext(trustFactory);
|
||||
return createSSLEngine(customTruststoreSSLContext);
|
||||
}
|
||||
|
||||
private SSLEngine createSSLEngine(SSLContext sslContext) {
|
||||
SSLEngine sslEngine = sslContext.createSSLEngine();
|
||||
try {
|
||||
sslEngine.setEnabledCipherSuites(ciphers);
|
||||
} catch (Throwable t) {
|
||||
throw new ElasticsearchSSLException("Error loading cipher suites ["+ Arrays.asList(ciphers)+"]", t);
|
||||
throw new ElasticsearchSSLException("Error loading cipher suites [" + Arrays.asList(ciphers) + "]", t);
|
||||
}
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
private KeyManagerFactory createKeyManagerFactory(String keyStore, String keyStorePassword, String keyStoreAlgorithm) {
|
||||
try (FileInputStream in = new FileInputStream(keyStore)) {
|
||||
// Load KeyStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
ks.load(in, keyStorePassword.toCharArray());
|
||||
|
||||
// Initialize KeyManagerFactory
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm);
|
||||
kmf.init(ks, keyStorePassword.toCharArray());
|
||||
return kmf;
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchSSLException("Failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
private SSLContext createSslContext(TrustManagerFactory trustFactory) {
|
||||
// Initialize sslContext
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance(sslProtocol);
|
||||
sslContext.init(keyManagerFactory.getKeyManagers(), trustFactory.getTrustManagers(), null);
|
||||
return sslContext;
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchSSLException("Failed to initialize the SSLContext", e);
|
||||
}
|
||||
}
|
||||
|
||||
private TrustManagerFactory getTrustFactory(String trustStore, String trustStorePassword, String trustStoreAlgorithm) {
|
||||
try (FileInputStream in = new FileInputStream(trustStore)) {
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
ks.load(in, trustStorePassword == null ? null : trustStorePassword.toCharArray());
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
return trustFactory;
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("Failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSSLEnabled(Settings settings) {
|
||||
return settings.getAsBoolean(SHIELD_TRANSPORT_SSL, false) ||
|
||||
settings.getAsBoolean(SHIELD_HTTP_SSL, false) ||
|
||||
|
|
|
@ -8,13 +8,11 @@ package org.elasticsearch.shield.transport;
|
|||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.inject.PreProcessModule;
|
||||
import org.elasticsearch.common.inject.util.Providers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.shield.SecurityFilter;
|
||||
import org.elasticsearch.shield.plugin.ShieldPlugin;
|
||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||
import org.elasticsearch.shield.transport.n2n.IPFilteringN2NAuthenticator;
|
||||
import org.elasticsearch.shield.transport.netty.N2NNettyUpstreamHandler;
|
||||
import org.elasticsearch.shield.transport.netty.NettySecuredHttpServerTransportModule;
|
||||
import org.elasticsearch.shield.transport.netty.NettySecuredTransportModule;
|
||||
import org.elasticsearch.transport.TransportModule;
|
||||
|
@ -52,7 +50,6 @@ public class SecuredTransportModule extends AbstractShieldModule.Spawn implement
|
|||
|
||||
if (clientMode) {
|
||||
// no ip filtering on the client
|
||||
bind(N2NNettyUpstreamHandler.class).toProvider(Providers.<N2NNettyUpstreamHandler>of(null));
|
||||
bind(ServerTransportFilter.class).toInstance(ServerTransportFilter.NOOP);
|
||||
return;
|
||||
}
|
||||
|
@ -60,9 +57,6 @@ public class SecuredTransportModule extends AbstractShieldModule.Spawn implement
|
|||
bind(ServerTransportFilter.class).to(SecurityFilter.ServerTransport.class).asEagerSingleton();
|
||||
if (settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true)) {
|
||||
bind(IPFilteringN2NAuthenticator.class).asEagerSingleton();
|
||||
bind(N2NNettyUpstreamHandler.class).asEagerSingleton();
|
||||
} else {
|
||||
bind(N2NNettyUpstreamHandler.class).toProvider(Providers.<N2NNettyUpstreamHandler>of(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,11 +41,11 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
|
||||
private static final Pattern COMMA_DELIM = Pattern.compile("\\s*,\\s*");
|
||||
private static final String DEFAULT_FILE = "ip_filter.yml";
|
||||
private static final IpFilterRule[] NO_RULES = new IpFilterRule[0];
|
||||
private static final ProfileIpFilterRule[] NO_RULES = new ProfileIpFilterRule[0];
|
||||
|
||||
private final Path file;
|
||||
|
||||
private volatile IpFilterRule[] rules = NO_RULES;
|
||||
private volatile ProfileIpFilterRule[] rules = NO_RULES;
|
||||
|
||||
@Inject
|
||||
public IPFilteringN2NAuthenticator(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
||||
|
@ -65,12 +65,12 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
return Paths.get(location);
|
||||
}
|
||||
|
||||
public static IpFilterRule[] parseFile(Path path, ESLogger logger) {
|
||||
public static ProfileIpFilterRule[] parseFile(Path path, ESLogger logger) {
|
||||
if (!Files.exists(path)) {
|
||||
return NO_RULES;
|
||||
}
|
||||
|
||||
List<IpFilterRule> rules = new ArrayList<>();
|
||||
List<ProfileIpFilterRule> rules = new ArrayList<>();
|
||||
|
||||
try (XContentParser parser = YamlXContent.yamlXContent.createParser(Files.newInputStream(path))) {
|
||||
XContentParser.Token token;
|
||||
|
@ -78,8 +78,8 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT && token != null) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
if (!"allow".equals(currentFieldName) && !"deny".equals(currentFieldName)) {
|
||||
throw new ElasticsearchParseException("Field name [" + currentFieldName + "] not valid. Must be [allow] or [deny]");
|
||||
if (!currentFieldName.endsWith("allow") && !currentFieldName.endsWith("deny")) {
|
||||
throw new ElasticsearchParseException("Field name [" + currentFieldName + "] not valid. Must be [allow] or [deny] or using a profile");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_STRING && currentFieldName != null) {
|
||||
String value = parser.text();
|
||||
|
@ -87,14 +87,15 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
throw new ElasticsearchParseException("Field value for fieldname [" + currentFieldName + "] must not be empty");
|
||||
}
|
||||
|
||||
boolean isAllowRule = currentFieldName.equals("allow");
|
||||
boolean isAllowRule = currentFieldName.endsWith("allow");
|
||||
String profile = currentFieldName.contains(".") ? currentFieldName.substring(0, currentFieldName.indexOf(".")) : "default";
|
||||
|
||||
if (value.contains(",")) {
|
||||
for (String rule : COMMA_DELIM.split(parser.text().trim())) {
|
||||
rules.add(getRule(isAllowRule, rule));
|
||||
rules.add(new ProfileIpFilterRule(profile, getRule(isAllowRule, rule)));
|
||||
}
|
||||
} else {
|
||||
rules.add(getRule(isAllowRule, value));
|
||||
rules.add(new ProfileIpFilterRule(profile, getRule(isAllowRule, value)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
}
|
||||
|
||||
logger.debug("Loaded {} ip filtering rules", rules.size());
|
||||
return rules.toArray(new IpFilterRule[rules.size()]);
|
||||
return rules.toArray(new ProfileIpFilterRule[rules.size()]);
|
||||
}
|
||||
|
||||
private static IpFilterRule getRule(boolean isAllowRule, String value) throws UnknownHostException {
|
||||
|
@ -124,9 +125,9 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort) {
|
||||
for (IpFilterRule rule : rules) {
|
||||
if (rule.contains(peerAddress)) {
|
||||
public boolean authenticate(@Nullable Principal peerPrincipal, String profile, InetAddress peerAddress, int peerPort) {
|
||||
for (ProfileIpFilterRule rule : rules) {
|
||||
if (rule.contains(profile, peerAddress)) {
|
||||
boolean isAllowed = rule.isAllowRule();
|
||||
logger.trace("Authentication rule matched for host [{}]: {}", peerAddress, isAllowed);
|
||||
return isAllowed;
|
||||
|
|
|
@ -15,32 +15,6 @@ import java.security.Principal;
|
|||
*/
|
||||
public interface N2NAuthenticator {
|
||||
|
||||
N2NAuthenticator NO_AUTH = new N2NAuthenticator() {
|
||||
@Override
|
||||
public boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
boolean authenticate(@Nullable Principal peerPrincipal, @Nullable String profile, InetAddress peerAddress, int peerPort);
|
||||
|
||||
boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort);
|
||||
|
||||
|
||||
class Compound implements N2NAuthenticator {
|
||||
|
||||
private N2NAuthenticator[] authenticators;
|
||||
|
||||
public Compound(N2NAuthenticator... authenticators) {
|
||||
this.authenticators = authenticators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort) {
|
||||
for (int i = 0; i < authenticators.length; i++) {
|
||||
if (!authenticators[i].authenticate(peerPrincipal, peerAddress, peerPort)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.shield.transport.n2n;
|
||||
|
||||
import org.elasticsearch.common.netty.handler.ipfilter.IpFilterRule;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* helper interface for filter rules, which takes a tcp transport profile into account
|
||||
*/
|
||||
public class ProfileIpFilterRule {
|
||||
|
||||
private final String profile;
|
||||
private final IpFilterRule ipFilterRule;
|
||||
|
||||
public ProfileIpFilterRule(String profile, IpFilterRule ipFilterRule) {
|
||||
this.profile = profile;
|
||||
this.ipFilterRule = ipFilterRule;
|
||||
}
|
||||
|
||||
public boolean contains(String profile, InetAddress inetAddress) {
|
||||
return this.profile.equals(profile) && ipFilterRule.contains(inetAddress);
|
||||
}
|
||||
|
||||
public boolean isAllowRule() {
|
||||
return ipFilterRule.isAllowRule();
|
||||
}
|
||||
|
||||
public boolean isDenyRule() {
|
||||
return ipFilterRule.isDenyRule();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.transport.netty;
|
||||
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.netty.channel.ChannelEvent;
|
||||
import org.elasticsearch.common.netty.channel.ChannelHandler;
|
||||
import org.elasticsearch.common.netty.channel.ChannelHandlerContext;
|
||||
|
@ -20,17 +19,18 @@ import java.net.InetSocketAddress;
|
|||
@ChannelHandler.Sharable
|
||||
public class N2NNettyUpstreamHandler extends IpFilteringHandlerImpl {
|
||||
|
||||
private IPFilteringN2NAuthenticator authenticator;
|
||||
private final IPFilteringN2NAuthenticator authenticator;
|
||||
private final String profile;
|
||||
|
||||
@Inject
|
||||
public N2NNettyUpstreamHandler(IPFilteringN2NAuthenticator authenticator) {
|
||||
public N2NNettyUpstreamHandler(IPFilteringN2NAuthenticator authenticator, String profile) {
|
||||
this.authenticator = authenticator;
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accept(ChannelHandlerContext channelHandlerContext, ChannelEvent channelEvent, InetSocketAddress inetSocketAddress) throws Exception {
|
||||
// at this stage no auth has happened, so we do not have any principal anyway
|
||||
return authenticator.authenticate(null, inetSocketAddress.getAddress(), inetSocketAddress.getPort());
|
||||
return authenticator.authenticate(null, profile, inetSocketAddress.getAddress(), inetSocketAddress.getPort());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.http.netty.NettyHttpServerTransport;
|
||||
import org.elasticsearch.shield.ssl.SSLService;
|
||||
import org.elasticsearch.shield.transport.n2n.IPFilteringN2NAuthenticator;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
|
@ -24,17 +25,19 @@ import javax.net.ssl.SSLEngine;
|
|||
public class NettySecuredHttpServerTransport extends NettyHttpServerTransport {
|
||||
|
||||
private final boolean ssl;
|
||||
private final N2NNettyUpstreamHandler shieldUpstreamHandler;
|
||||
private final boolean ipFilterEnabled;
|
||||
private final IPFilteringN2NAuthenticator authenticator;
|
||||
private final SSLService sslService;
|
||||
|
||||
@Inject
|
||||
public NettySecuredHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays,
|
||||
@Nullable N2NNettyUpstreamHandler shieldUpstreamHandler, @Nullable SSLService sslService) {
|
||||
@Nullable IPFilteringN2NAuthenticator authenticator, @Nullable SSLService sslService) {
|
||||
super(settings, networkService, bigArrays);
|
||||
this.authenticator = authenticator;
|
||||
this.ssl = settings.getAsBoolean("shield.http.ssl", false);
|
||||
this.sslService = sslService;
|
||||
this.shieldUpstreamHandler = shieldUpstreamHandler;
|
||||
assert !ssl || sslService != null : "ssl is enabled yet the ssl service is null";
|
||||
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,8 +61,8 @@ public class NettySecuredHttpServerTransport extends NettyHttpServerTransport {
|
|||
|
||||
pipeline.addFirst("ssl", new SslHandler(engine));
|
||||
}
|
||||
if (shieldUpstreamHandler != null) {
|
||||
pipeline.addFirst("ipfilter", shieldUpstreamHandler);
|
||||
if (ipFilterEnabled) {
|
||||
pipeline.addFirst("ipfilter", new N2NNettyUpstreamHandler(authenticator, "default"));
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.network.NetworkService;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.shield.ssl.SSLService;
|
||||
import org.elasticsearch.shield.transport.n2n.IPFilteringN2NAuthenticator;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty.NettyTransport;
|
||||
|
||||
|
@ -26,16 +27,18 @@ import javax.net.ssl.SSLEngine;
|
|||
public class NettySecuredTransport extends NettyTransport {
|
||||
|
||||
private final boolean ssl;
|
||||
private final N2NNettyUpstreamHandler shieldUpstreamHandler;
|
||||
private final SSLService sslService;
|
||||
private final boolean ipFilterEnabled;
|
||||
private final IPFilteringN2NAuthenticator authenticator;
|
||||
|
||||
@Inject
|
||||
public NettySecuredTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version,
|
||||
@Nullable N2NNettyUpstreamHandler shieldUpstreamHandler, @Nullable SSLService sslService) {
|
||||
@Nullable IPFilteringN2NAuthenticator authenticator, @Nullable SSLService sslService) {
|
||||
super(settings, threadPool, networkService, bigArrays, version);
|
||||
this.shieldUpstreamHandler = shieldUpstreamHandler;
|
||||
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
|
||||
this.authenticator = authenticator;
|
||||
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true);
|
||||
this.sslService = sslService;
|
||||
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
|
||||
assert !ssl || sslService != null : "ssl is enabled yet the ssl service is null";
|
||||
}
|
||||
|
||||
|
@ -51,23 +54,31 @@ public class NettySecuredTransport extends NettyTransport {
|
|||
|
||||
private class SslServerChannelPipelineFactory extends ServerChannelPipelineFactory {
|
||||
|
||||
private final Settings profileSettings;
|
||||
|
||||
public SslServerChannelPipelineFactory(NettyTransport nettyTransport, String name, Settings settings, Settings profileSettings) {
|
||||
super(nettyTransport, name, settings);
|
||||
this.profileSettings = profileSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (ssl) {
|
||||
SSLEngine serverEngine = sslService.createSSLEngine();
|
||||
SSLEngine serverEngine;
|
||||
if (profileSettings.get("shield.truststore.path") != null) {
|
||||
serverEngine = sslService.createSSLEngineWithTruststore(profileSettings.getByPrefix("shield."));
|
||||
} else {
|
||||
serverEngine = sslService.createSSLEngine();
|
||||
}
|
||||
serverEngine.setUseClientMode(false);
|
||||
serverEngine.setNeedClientAuth(true);
|
||||
|
||||
pipeline.addFirst("ssl", new SslHandler(serverEngine));
|
||||
pipeline.replace("dispatcher", "dispatcher", new SecuredMessageChannelHandler(nettyTransport, logger));
|
||||
}
|
||||
if (shieldUpstreamHandler != null) {
|
||||
pipeline.addFirst("ipfilter", shieldUpstreamHandler);
|
||||
if (ipFilterEnabled) {
|
||||
pipeline.addFirst("ipfilter", new N2NNettyUpstreamHandler(authenticator, name));
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||
public static void setTrustStore() throws URISyntaxException {
|
||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
||||
.put("shield.ssl.keystore", filename)
|
||||
.put("shield.ssl.keystore_password", "changeit")
|
||||
.put("shield.ssl.keystore.path", filename)
|
||||
.put("shield.ssl.keystore.password", "changeit")
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ package org.elasticsearch.shield.authc.ldap;
|
|||
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.shield.ssl.SSLService;
|
||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
||||
import org.elasticsearch.shield.ssl.SSLService;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -25,14 +25,13 @@ import static org.hamcrest.Matchers.hasItem;
|
|||
public class OpenLdapTests extends ElasticsearchTestCase {
|
||||
public static final String OPEN_LDAP_URL = "ldaps://54.200.235.244:636";
|
||||
public static final String PASSWORD = "NickFuryHeartsES";
|
||||
public static final String SETTINGS_PREFIX = LdapRealm.class.getPackage().getName().substring("com.elasticsearch.".length()) + '.';
|
||||
|
||||
@BeforeClass
|
||||
public static void setTrustStore() throws URISyntaxException {
|
||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
||||
.put("shield.ssl.keystore", filename)
|
||||
.put("shield.ssl.keystore_password", "changeit")
|
||||
.put("shield.ssl.keystore.path", filename)
|
||||
.put("shield.ssl.keystore.password", "changeit")
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ public class LdapSslSocketFactoryTests extends ElasticsearchTestCase {
|
|||
public static void setTrustStore() throws URISyntaxException {
|
||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
||||
.put("shield.ssl.keystore", filename)
|
||||
.put("shield.ssl.keystore_password", "changeit")
|
||||
.put("shield.ssl.keystore.path", filename)
|
||||
.put("shield.ssl.keystore.password", "changeit")
|
||||
.build()));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.elasticsearch.http.HttpServerTransport;
|
|||
import org.elasticsearch.node.internal.InternalNode;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.test.ShieldIntegrationTest;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
|
||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
||||
import org.junit.Test;
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.ssl;
|
||||
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.io.File;
|
||||
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class SSLServiceTests extends ElasticsearchTestCase {
|
||||
|
||||
|
@ -30,10 +31,10 @@ public class SSLServiceTests extends ElasticsearchTestCase {
|
|||
public void testThatInvalidProtocolThrowsException() throws Exception {
|
||||
new SSLService(settingsBuilder()
|
||||
.put("shield.ssl.protocol", "non-existing")
|
||||
.put("shield.ssl.keystore", testnodeStore.getPath())
|
||||
.put("shield.ssl.keystore_password", "testnode")
|
||||
.put("shield.ssl.truststore", testnodeStore.getPath())
|
||||
.put("shield.ssl.truststore_password", "testnode")
|
||||
.put("shield.ssl.keystore.path", testnodeStore.getPath())
|
||||
.put("shield.ssl.keystore.password", "testnode")
|
||||
.put("shield.ssl.truststore.path", testnodeStore.getPath())
|
||||
.put("shield.ssl.truststore.password", "testnode")
|
||||
.build());
|
||||
}
|
||||
|
||||
|
@ -41,10 +42,10 @@ public class SSLServiceTests extends ElasticsearchTestCase {
|
|||
public void testSpecificProtocol() {
|
||||
SSLService ssl = new SSLService(settingsBuilder()
|
||||
.put("shield.ssl.protocol", "TLSv1.2")
|
||||
.put("shield.ssl.keystore", testnodeStore.getPath())
|
||||
.put("shield.ssl.keystore_password", "testnode")
|
||||
.put("shield.ssl.truststore", testnodeStore.getPath())
|
||||
.put("shield.ssl.truststore_password", "testnode")
|
||||
.put("shield.ssl.keystore.path", testnodeStore.getPath())
|
||||
.put("shield.ssl.keystore.password", "testnode")
|
||||
.put("shield.ssl.truststore.path", testnodeStore.getPath())
|
||||
.put("shield.ssl.truststore.password", "testnode")
|
||||
.build());
|
||||
assertThat(ssl.createSSLEngine().getSSLParameters().getProtocols(), arrayContaining("TLSv1.2"));
|
||||
}
|
||||
|
@ -111,6 +112,23 @@ public class SSLServiceTests extends ElasticsearchTestCase {
|
|||
assertSSLEnabled(settings);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
|
||||
File testClientStore = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
|
||||
|
||||
SSLService sslService = new SSLService(settingsBuilder()
|
||||
.put("shield.ssl.keystore.path", testnodeStore.getPath())
|
||||
.put("shield.ssl.keystore.password", "testnode")
|
||||
.build());
|
||||
|
||||
ImmutableSettings.Builder settingsBuilder = settingsBuilder()
|
||||
.put("truststore.path", testClientStore.getPath())
|
||||
.put("truststore.password", "testclient");
|
||||
|
||||
SSLEngine sslEngineWithTruststore = sslService.createSSLEngineWithTruststore(settingsBuilder.build());
|
||||
assertThat(sslEngineWithTruststore, is(not(nullValue())));
|
||||
}
|
||||
|
||||
private void assertSSLEnabled(Settings settings) {
|
||||
assertThat(SSLService.isSSLEnabled(settings), is(true));
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ import com.google.common.base.Charsets;
|
|||
import com.google.common.net.InetAddresses;
|
||||
import org.apache.lucene.util.AbstractRandomizedTest;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.os.OsUtils;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
|
@ -34,6 +37,7 @@ import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilde
|
|||
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
|
@ -158,13 +162,13 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest
|
|||
|
||||
ImmutableSettings.Builder builder = settingsBuilder()
|
||||
.put("shield.transport.ssl", true)
|
||||
.put("shield.ssl.keystore", store.getPath())
|
||||
.put("shield.ssl.keystore_password", password)
|
||||
.put("shield.ssl.keystore.path", store.getPath())
|
||||
.put("shield.ssl.keystore.password", password)
|
||||
.put("shield.http.ssl", true);
|
||||
|
||||
if (randomBoolean()) {
|
||||
builder.put("shield.ssl.truststore", store.getPath())
|
||||
.put("shield.ssl.truststore_password", password);
|
||||
builder.put("shield.ssl.truststore.path", store.getPath())
|
||||
.put("shield.ssl.truststore.password", password);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
@ -179,4 +183,10 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertGreenClusterState(Client client) {
|
||||
ClusterHealthResponse clusterHealthResponse = client.admin().cluster().prepareHealth().get();
|
||||
assertNoTimeout(clusterHealthResponse);
|
||||
assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.unit.TimeValue;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.junit.After;
|
||||
|
@ -141,6 +142,17 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
|
|||
assertAddressIsAllowed("127.0.0.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestLogging("_root:TRACE")
|
||||
public void testThatProfilesAreSupported() throws Exception {
|
||||
writeConfigFile("allow: localhost\ndeny: all\nclient.allow: 192.168.0.1\nclient.deny: all");
|
||||
|
||||
assertAddressIsAllowed("127.0.0.1");
|
||||
assertAddressIsDenied("192.168.0.1");
|
||||
assertAddressIsAllowedForProfile("client", "192.168.0.1");
|
||||
assertAddressIsDeniedForProfile("client", "192.168.0.2");
|
||||
}
|
||||
|
||||
@Test(expected = ElasticsearchParseException.class)
|
||||
public void testThatInvalidFileThrowsCorrectException() throws Exception {
|
||||
writeConfigFile("deny: all allow: all \n\n");
|
||||
|
@ -155,17 +167,25 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
|
|||
ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService);
|
||||
}
|
||||
|
||||
private void assertAddressIsAllowed(String ... inetAddresses) {
|
||||
private void assertAddressIsAllowedForProfile(String profile, String ... inetAddresses) {
|
||||
for (String inetAddress : inetAddresses) {
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be allowed", inetAddress);
|
||||
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(true));
|
||||
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, profile, InetAddresses.forString(inetAddress), 1024), is(true));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAddressIsAllowed(String ... inetAddresses) {
|
||||
assertAddressIsAllowedForProfile("default", inetAddresses);
|
||||
}
|
||||
|
||||
private void assertAddressIsDeniedForProfile(String profile, String ... inetAddresses) {
|
||||
for (String inetAddress : inetAddresses) {
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be denied", inetAddress);
|
||||
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, profile, InetAddresses.forString(inetAddress), 1024), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAddressIsDenied(String ... inetAddresses) {
|
||||
for (String inetAddress : inetAddresses) {
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be denied", inetAddress);
|
||||
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(false));
|
||||
}
|
||||
assertAddressIsDeniedForProfile("default", inetAddresses);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class N2NNettyUpstreamHandlerTests extends ElasticsearchTestCase {
|
|||
Settings settings = settingsBuilder().put("shield.transport.n2n.ip_filter.file", configFile.getPath()).build();
|
||||
IPFilteringN2NAuthenticator ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService);
|
||||
|
||||
nettyUpstreamHandler = new N2NNettyUpstreamHandler(ipFilteringN2NAuthenticator);
|
||||
nettyUpstreamHandler = new N2NNettyUpstreamHandler(ipFilteringN2NAuthenticator, "default");
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -181,10 +181,4 @@ public class SslIntegrationTests extends ShieldIntegrationTest {
|
|||
String data = Streams.copyToString(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8));
|
||||
assertThat(data, containsString("You Know, for Search"));
|
||||
}
|
||||
|
||||
private void assertGreenClusterState(Client client) {
|
||||
ClusterHealthResponse clusterHealthResponse = client.admin().cluster().prepareHealth().get();
|
||||
assertNoTimeout(clusterHealthResponse);
|
||||
assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.shield.transport.ssl;
|
||||
|
||||
import org.elasticsearch.client.transport.NoNodeAvailableException;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.plugins.PluginsService;
|
||||
import org.elasticsearch.shield.test.ShieldIntegrationTest;
|
||||
import org.elasticsearch.shield.transport.netty.NettySecuredTransport;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportModule;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SslMultiPortTests extends ShieldIntegrationTest {
|
||||
|
||||
private ImmutableSettings.Builder builder;
|
||||
private static int randomClientPort;
|
||||
|
||||
@BeforeClass
|
||||
public static void getRandomPort() {
|
||||
randomClientPort = randomIntBetween(49000, 65500); // ephemeral port
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupBuilder() {
|
||||
builder = settingsBuilder()
|
||||
.put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
|
||||
.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
|
||||
.put("node.mode", "network")
|
||||
.put("cluster.name", internalCluster().getClusterName());
|
||||
|
||||
setUser(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
String randomClientPortRange = randomClientPort + "-" + (randomClientPort+100);
|
||||
|
||||
File store;
|
||||
try {
|
||||
store = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-client-profile.jks").toURI());
|
||||
assertThat(store.exists(), is(true));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return settingsBuilder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
// settings for default key profile
|
||||
.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode"))
|
||||
// client set up here
|
||||
.put("transport.profiles.client.port", randomClientPortRange)
|
||||
.put("transport.profiles.client.bind_host", "localhost") // make sure this is "localhost", no matter if ipv4 or ipv6, but be consistent
|
||||
.put("transport.profiles.client.shield.truststore.path", store.getAbsolutePath()) // settings for client truststore
|
||||
.put("transport.profiles.client.shield.truststore.password", "testnode-client-profile")
|
||||
.put("shield.audit.enabled", false )
|
||||
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatStandardTransportClientCanConnectToDefaultProfile() throws Exception {
|
||||
builder.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"));
|
||||
try (TransportClient transportClient = new TransportClient(builder, false)) {
|
||||
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
|
||||
transportClient.addTransportAddress(transportAddress);
|
||||
assertGreenClusterState(transportClient);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = NoNodeAvailableException.class)
|
||||
public void testThatStandardTransportClientCannotConnectToClientProfile() throws Exception {
|
||||
builder.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"));
|
||||
try (TransportClient transportClient = new TransportClient(builder, false)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress("localhost", randomClientPort));
|
||||
transportClient.admin().cluster().prepareHealth().get();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThatProfileTransportClientCanConnectToClientProfile() throws Exception {
|
||||
builder.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"));
|
||||
try (TransportClient transportClient = new TransportClient(builder, false)) {
|
||||
transportClient.addTransportAddress(new InetSocketTransportAddress("localhost", randomClientPort));
|
||||
assertGreenClusterState(transportClient);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = NoNodeAvailableException.class)
|
||||
public void testThatProfileTransportClientCannotConnectToDefaultProfile() throws Exception {
|
||||
builder.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"));
|
||||
try (TransportClient transportClient = new TransportClient(builder, false)) {
|
||||
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
|
||||
transportClient.addTransportAddress(transportAddress);
|
||||
transportClient.admin().cluster().prepareHealth().get();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,10 +109,10 @@ public class ShieldRestTests extends ElasticsearchRestTests {
|
|||
.put("shield.authz.store.files.roles", createFile(folder, "roles.yml", CONFIG_ROLE_ALLOW_ALL))
|
||||
.put("shield.transport.n2n.ip_filter.file", createFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL))
|
||||
.put("shield.transport.ssl", ENABLE_TRANSPORT_SSL)
|
||||
.put("shield.ssl.keystore", store.getPath())
|
||||
.put("shield.ssl.keystore_password", password)
|
||||
.put("shield.ssl.truststore", store.getPath())
|
||||
.put("shield.ssl.truststore_password", password)
|
||||
.put("shield.ssl.keystore.path", store.getPath())
|
||||
.put("shield.ssl.keystore.password", password)
|
||||
.put("shield.ssl.truststore.path", store.getPath())
|
||||
.put("shield.ssl.truststore.password", password)
|
||||
.put("shield.http.ssl", false)
|
||||
.put("transport.tcp.port", BASE_PORT_RANGE)
|
||||
.putArray("discovery.zen.ping.unicast.hosts", "127.0.0.1:" + BASE_PORT, "127.0.0.1:" + (BASE_PORT + 1), "127.0.0.1:" + (BASE_PORT + 2), "127.0.0.1:" + (BASE_PORT + 3))
|
||||
|
@ -146,10 +146,10 @@ public class ShieldRestTests extends ElasticsearchRestTests {
|
|||
.put("node.mode", "network")
|
||||
.put("shield.transport.n2n.ip_filter.file", createFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL))
|
||||
.put("shield.transport.ssl", ENABLE_TRANSPORT_SSL)
|
||||
.put("shield.ssl.keystore", store.getPath())
|
||||
.put("shield.ssl.keystore_password", password)
|
||||
.put("shield.ssl.truststore", store.getPath())
|
||||
.put("shield.ssl.truststore_password", password)
|
||||
.put("shield.ssl.keystore.path", store.getPath())
|
||||
.put("shield.ssl.keystore.password", password)
|
||||
.put("shield.ssl.truststore.path", store.getPath())
|
||||
.put("shield.ssl.truststore.password", password)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIEWHpBBTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAw
|
||||
DgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYD
|
||||
VQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MTEwNTEwMzMxMVoXDTE1MDIwMzEw
|
||||
MzMxMVowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5r
|
||||
bm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93
|
||||
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANMk6NoZl5kbrt9ycsCAms/aivFvmd17
|
||||
OTwNPqVvsEa7/uCdaDAiYvUtdjs8LMh7uN5s/6DuimpmbKh/XmT9wljWGpT/zPQQhhontvxefXCr
|
||||
Gp6z8Bs6z/xrbN8GU+M6D4AFOOnZ8YdlXEmFrCCdp7Nu6eqEUa5ui/1HLrTvey0xN2geZHwfHyPw
|
||||
ZY9eRlLn2v9lzilzrd3H8AIJ4vBBUx44/CP90ocYUSArLOm8TFvRSOfp/vqz0j6gnGOebN9e4a0B
|
||||
gAZVQmN8g+SrJsRNGgjGgLj7AjQxh9iThpWIWNeJ2UTeuswvANvxna0zRcr6fejmtaAYO9SST76c
|
||||
oaZSvS0CAwEAAaMhMB8wHQYDVR0OBBYEFJnOrwiIIEz8XMVIXL8g3QRgtUafMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQCYQW+1efFngQbxDs1jZp+rBAeQ2rQFc4arWx4HOCaRyjlPCwNpjwlN3JM+OtqqR4Z/
|
||||
1HMRpPjgdayiTQ3HsVRWzMVm4NCVHx5LmahMCHv+1mru4Ut7BbbupgAlsQ3vtKcgKIdTVhO8vJlP
|
||||
IYprm388k06/t3CuQJSaCNxElpe3kIldXMeFRKi2TcqOXjb/Nw2L+gZz/+XJLWLOmoAy+2Pq629f
|
||||
bk1d/lG3pf0QV/X1kcMiHV320iI/CZJWvwuJK73Ukg1RG8CTYt649R1Trqns6bimFyOMMnBlNtD5
|
||||
PJiZ0+528XTNbA6Vhz/bXN2g7lDtedy6xJSO1ULFFE9/iUKX
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIEHucrFzANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAw
|
||||
DgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYD
|
||||
VQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE0MTEwNDE3MTUxNVoXDTE1MDIwMjE3
|
||||
MTUxNVowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5r
|
||||
bm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93
|
||||
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrBa2XNWQUk8+TdwG1ZSiwGfQOKNQko
|
||||
JoX7Cx977L3RQIEs9Q2JxsSRM3wh4uBZzrZ/NCnxKOtw3bKC6B9dUJLXXwZFc7YTtNfcZr8S2000
|
||||
UW6mre/4u54wnkJD/ahuoZ/FCUE7ETB+Jeg3uDhyoUCcySo96OPvZpy/ctXTmkDuai3h+0NvUgpY
|
||||
yll2LcWBaottW0X6YveCwF78CNDVCSLRjGKqLa3QWFGFMQWdmYrzIaCb1e4U0/8WHM0ylw/vYuvz
|
||||
u+BDXOsoIPUn4eDdeWtxXA/ZGhjDCfTb0GWSSBfmciMY6yIBpQalt/yRQ/2AL9t+G2fc0th2FzD6
|
||||
2UZOexMCAwEAAaMhMB8wHQYDVR0OBBYEFEL891TiYG3R/E5kGjxVY+SwAY5BMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQB372cFMKkLlnH2JbMMtVooXWjF40TJdUOU/ImB+i7rLdVUFX/HmexiL3nDziwOMhTH
|
||||
N3iEDlxcBeVP+XxZouStwAZP0MmezoGiEjRG53w8gBHSkiWmkKBHYZe1JedeZxEWQCCI0zMh14PY
|
||||
j5kmgD/sFSvWJCP8UpJnSKTj4ZKAiITmsgSJL/0A5R2Af2lTD5k5sQyvNt1im6atuKdnO96Iqthr
|
||||
8WRpeyOh5xDZht/KGphZSQyjEpF/RVXWXstkqrKMZRZlKW0EcuBHX4EsTNuzRYC19ReD7d2/CM5M
|
||||
u9u+iTR1Kws0r3YX4cMnlLXVzJPlAzUrbXmYAMYtpbbYT9QW
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue