Remove netty_3 support from xpack (elastic/elasticsearch#4097)
This is a followup from elastic/elasticsearchelastic/elasticsearch#21590 and needs to be committed first or at the same time since netty_3 is removed Original commit: elastic/x-pack-elasticsearch@131d74dd6b
This commit is contained in:
parent
a5e410ba59
commit
92040ef72e
|
@ -31,7 +31,6 @@ licenseHeaders {
|
|||
|
||||
dependencies {
|
||||
// security deps
|
||||
compile project(path: ':modules:transport-netty3', configuration: 'runtime')
|
||||
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
|
||||
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
|
||||
compile 'org.bouncycastle:bcprov-jdk15on:1.55'
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.common.http;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
|
@ -21,7 +22,6 @@ import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
|||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.common.http;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
|
@ -16,7 +17,6 @@ import org.elasticsearch.common.xcontent.ToXContent;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -114,8 +114,6 @@ import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction;
|
|||
import org.elasticsearch.xpack.security.rest.action.user.RestSetEnabledAction;
|
||||
import org.elasticsearch.xpack.security.transport.SecurityServerTransportInterceptor;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
|
@ -145,7 +143,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
|
||||
private static final Logger logger = Loggers.getLogger(XPackPlugin.class);
|
||||
|
||||
public static final String NAME3 = XPackPlugin.SECURITY + "3";
|
||||
public static final String NAME4 = XPackPlugin.SECURITY + "4";
|
||||
public static final Setting<Optional<String>> USER_SETTING =
|
||||
new Setting<>(setting("user"), (String) null, Optional::ofNullable, Property.NodeScope);
|
||||
|
@ -354,9 +351,9 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
|
||||
if (NetworkModule.TRANSPORT_TYPE_SETTING.exists(settings)) {
|
||||
final String transportType = NetworkModule.TRANSPORT_TYPE_SETTING.get(settings);
|
||||
if (NAME3.equals(transportType) == false && NAME4.equals(transportType) == false) {
|
||||
throw new IllegalArgumentException("transport type setting [" + NetworkModule.TRANSPORT_TYPE_KEY + "] must be one of [" +
|
||||
NAME3 + "," + NAME4 + "]");
|
||||
if (NAME4.equals(transportType) == false) {
|
||||
throw new IllegalArgumentException("transport type setting [" + NetworkModule.TRANSPORT_TYPE_KEY + "] must be [" + NAME4
|
||||
+ "]");
|
||||
}
|
||||
} else {
|
||||
// default to security4
|
||||
|
@ -365,13 +362,10 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
|
||||
if (NetworkModule.HTTP_TYPE_SETTING.exists(settings)) {
|
||||
final String httpType = NetworkModule.HTTP_TYPE_SETTING.get(settings);
|
||||
if (httpType.equals(NAME3)) {
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(settingsBuilder, settings);
|
||||
} else if (httpType.equals(NAME4)) {
|
||||
if (httpType.equals(NAME4)) {
|
||||
SecurityNetty4HttpServerTransport.overrideSettings(settingsBuilder, settings);
|
||||
} else {
|
||||
throw new IllegalArgumentException("http type setting [" + NetworkModule.HTTP_TYPE_KEY + "] must be one of [" +
|
||||
NAME3 + "," + NAME4 + "]");
|
||||
throw new IllegalArgumentException("http type setting [" + NetworkModule.HTTP_TYPE_KEY + "] must be [" + NAME4 + "]");
|
||||
}
|
||||
} else {
|
||||
// default to security4
|
||||
|
@ -714,13 +708,8 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
if (enabled == false) { // don't register anything if we are not enabled
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, Supplier<Transport>> map = new HashMap<>();
|
||||
map.put(Security.NAME3, () -> new SecurityNetty3Transport(settings, threadPool, networkService, bigArrays, ipFilter.get(),
|
||||
sslService, namedWriteableRegistry, circuitBreakerService));
|
||||
map.put(Security.NAME4, () -> new SecurityNetty4Transport(settings, threadPool, networkService, bigArrays,
|
||||
return Collections.singletonMap(Security.NAME4, () -> new SecurityNetty4Transport(settings, threadPool, networkService, bigArrays,
|
||||
namedWriteableRegistry, circuitBreakerService, ipFilter.get(), sslService));
|
||||
return Collections.unmodifiableMap(map);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -731,12 +720,9 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
if (enabled == false) { // don't register anything if we are not enabled
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, Supplier<HttpServerTransport>> map = new HashMap<>();
|
||||
map.put(Security.NAME3, () -> new SecurityNetty3HttpServerTransport(settings, networkService, bigArrays, ipFilter.get(), sslService,
|
||||
return Collections.singletonMap(Security.NAME4, () -> new SecurityNetty4HttpServerTransport(settings, networkService, bigArrays,
|
||||
ipFilter.get(), sslService,
|
||||
threadPool));
|
||||
map.put(Security.NAME4, () -> new SecurityNetty4HttpServerTransport(settings, networkService, bigArrays, ipFilter.get(), sslService,
|
||||
threadPool));
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.authc.Realms;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.ssl.CertUtils;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
@ -23,7 +24,6 @@ import org.elasticsearch.xpack.security.authc.AuthenticationToken;
|
|||
import org.elasticsearch.xpack.security.authc.Realm;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
@ -226,9 +226,9 @@ public class PkiRealm extends Realm {
|
|||
Map<String, Settings> groupedSettings = settings.getGroups("transport.profiles.");
|
||||
for (Map.Entry<String, Settings> entry : groupedSettings.entrySet()) {
|
||||
Settings profileSettings = entry.getValue().getByPrefix(Security.settingPrefix());
|
||||
if (SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings)
|
||||
if (SecurityNetty4Transport.PROFILE_SSL_SETTING.get(profileSettings)
|
||||
&& sslService.isSSLClientAuthEnabled(
|
||||
SecurityNetty3Transport.profileSslSettings(profileSettings), transportSSLSettings)) {
|
||||
SecurityNetty4Transport.profileSslSettings(profileSettings), transportSSLSettings)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,14 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.rest;
|
||||
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.http.netty3.Netty3HttpRequest;
|
||||
import org.elasticsearch.http.netty4.Netty4HttpRequest;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
|
@ -25,14 +23,9 @@ import org.elasticsearch.rest.RestRequest;
|
|||
import org.elasticsearch.rest.RestRequest.Method;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
||||
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
|
||||
import org.elasticsearch.xpack.security.transport.ServerTransportFilter;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
|
||||
|
@ -70,7 +63,10 @@ public class SecurityRestFilter extends RestFilter {
|
|||
if (licenseState.isAuthAllowed() && request.method() != Method.OPTIONS) {
|
||||
// CORS - allow for preflight unauthenticated OPTIONS request
|
||||
if (extractClientCertificate) {
|
||||
putClientCertificateInContext(request, threadContext, logger);
|
||||
Netty4HttpRequest nettyHttpRequest = (Netty4HttpRequest) request;
|
||||
SslHandler handler = nettyHttpRequest.getChannel().pipeline().get(SslHandler.class);
|
||||
assert handler != null;
|
||||
ServerTransportFilter.extactClientCertificates(logger, threadContext, handler.engine(), nettyHttpRequest.getChannel());
|
||||
}
|
||||
service.authenticate(request, ActionListener.wrap((authentication) -> {
|
||||
RemoteHostHeader.process(request, threadContext);
|
||||
|
@ -80,42 +76,4 @@ public class SecurityRestFilter extends RestFilter {
|
|||
filterChain.continueProcessing(request, channel, client);
|
||||
}
|
||||
}
|
||||
|
||||
static void putClientCertificateInContext(RestRequest request, ThreadContext threadContext, Logger logger) throws Exception {
|
||||
assert request instanceof Netty3HttpRequest || request instanceof Netty4HttpRequest;
|
||||
if (request instanceof Netty3HttpRequest) {
|
||||
Netty3HttpRequest nettyHttpRequest = (Netty3HttpRequest) request;
|
||||
|
||||
SslHandler handler = nettyHttpRequest.getChannel().getPipeline().get(SslHandler.class);
|
||||
assert handler != null;
|
||||
extractClientCerts(handler.getEngine(), nettyHttpRequest.getChannel(), threadContext, logger);
|
||||
} else if (request instanceof Netty4HttpRequest) {
|
||||
Netty4HttpRequest nettyHttpRequest = (Netty4HttpRequest) request;
|
||||
|
||||
io.netty.handler.ssl.SslHandler handler = nettyHttpRequest.getChannel().pipeline().get(io.netty.handler.ssl.SslHandler.class);
|
||||
assert handler != null;
|
||||
extractClientCerts(handler.engine(), nettyHttpRequest.getChannel(), threadContext, logger);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void extractClientCerts(SSLEngine sslEngine, Object channel, ThreadContext threadContext, Logger logger) {
|
||||
try {
|
||||
Certificate[] certs = sslEngine.getSession().getPeerCertificates();
|
||||
if (certs instanceof X509Certificate[]) {
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// this happens when client authentication is optional and the client does not provide credentials. If client
|
||||
// authentication was required then this connection should be closed before ever getting into this class
|
||||
assert sslEngine.getNeedClientAuth() == false;
|
||||
assert sslEngine.getWantClientAuth();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage("SSL Peer did not present a certificate on channel [{}]", channel), e);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("SSL Peer did not present a certificate on channel [{}]", channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.transport;
|
||||
|
||||
import org.jboss.netty.handler.ssl.NotSslRecordException;
|
||||
|
||||
import io.netty.handler.ssl.NotSslRecordException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
|||
import org.elasticsearch.xpack.security.authz.AuthorizationService;
|
||||
import org.elasticsearch.xpack.security.authz.AuthorizationUtils;
|
||||
import org.elasticsearch.xpack.security.authz.accesscontrol.RequestContext;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
|
||||
import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
||||
|
@ -125,8 +125,8 @@ public class SecurityServerTransportInterceptor implements TransportInterceptor
|
|||
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||
for (Map.Entry<String, Settings> entry : profileSettingsMap.entrySet()) {
|
||||
Settings profileSettings = entry.getValue();
|
||||
final boolean profileSsl = SecurityNetty3Transport.PROFILE_SSL_SETTING.get(profileSettings);
|
||||
final Settings profileSslSettings = SecurityNetty3Transport.profileSslSettings(profileSettings);
|
||||
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;
|
||||
String type = entry.getValue().get(SETTING_NAME, "node");
|
||||
|
@ -152,10 +152,6 @@ public class SecurityServerTransportInterceptor implements TransportInterceptor
|
|||
return Collections.unmodifiableMap(profileFilters);
|
||||
}
|
||||
|
||||
ServerTransportFilter transportFilter(String profile) {
|
||||
return profileFilters.get(profile);
|
||||
}
|
||||
|
||||
public static class ProfileSecuredRequestHandler<T extends TransportRequest> implements TransportRequestHandler<T> {
|
||||
|
||||
protected final String action;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.transport;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
|
@ -25,8 +27,6 @@ import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
|||
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
|
||||
import org.elasticsearch.xpack.security.authz.AuthorizationService;
|
||||
import org.elasticsearch.xpack.security.authz.AuthorizationUtils;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
@ -100,19 +100,13 @@ public interface ServerTransportFilter {
|
|||
unwrappedChannel = ((DelegatingTransportChannel) unwrappedChannel).getChannel();
|
||||
}
|
||||
|
||||
if (extractClientCert && (unwrappedChannel instanceof TcpTransportChannel)) {
|
||||
if (((TcpTransportChannel) unwrappedChannel).getChannel() instanceof Channel) {
|
||||
Channel channel = (Channel) ((TcpTransportChannel) unwrappedChannel).getChannel();
|
||||
SslHandler sslHandler = channel.getPipeline().get(SslHandler.class);
|
||||
assert sslHandler != null;
|
||||
extactClientCertificates(sslHandler.getEngine(), channel);
|
||||
} else if (((TcpTransportChannel) unwrappedChannel).getChannel() instanceof io.netty.channel.Channel) {
|
||||
io.netty.channel.Channel channel = (io.netty.channel.Channel) ((TcpTransportChannel) unwrappedChannel).getChannel();
|
||||
io.netty.handler.ssl.SslHandler sslHandler = channel.pipeline().get(io.netty.handler.ssl.SslHandler.class);
|
||||
if (channel.isOpen()) {
|
||||
assert sslHandler != null : "channel [" + channel + "] did not have a ssl handler. pipeline " + channel.pipeline();
|
||||
extactClientCertificates(sslHandler.engine(), channel);
|
||||
}
|
||||
if (extractClientCert && (unwrappedChannel instanceof TcpTransportChannel) &&
|
||||
((TcpTransportChannel) unwrappedChannel).getChannel() instanceof io.netty.channel.Channel) {
|
||||
Channel channel = (io.netty.channel.Channel) ((TcpTransportChannel) unwrappedChannel).getChannel();
|
||||
SslHandler sslHandler = channel.pipeline().get(SslHandler.class);
|
||||
if (channel.isOpen()) {
|
||||
assert sslHandler != null : "channel [" + channel + "] did not have a ssl handler. pipeline " + channel.pipeline();
|
||||
extactClientCertificates(logger, threadContext, sslHandler.engine(), channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,25 +119,25 @@ public interface ServerTransportFilter {
|
|||
asyncAuthorizer.authorize(authzService);
|
||||
}, listener::onFailure));
|
||||
}
|
||||
}
|
||||
|
||||
private void extactClientCertificates(SSLEngine sslEngine, Object channel) {
|
||||
try {
|
||||
Certificate[] certs = sslEngine.getSession().getPeerCertificates();
|
||||
if (certs instanceof X509Certificate[]) {
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// this happens when client authentication is optional and the client does not provide credentials. If client
|
||||
// authentication was required then this connection should be closed before ever getting into this class
|
||||
assert sslEngine.getNeedClientAuth() == false;
|
||||
assert sslEngine.getWantClientAuth();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"SSL Peer did not present a certificate on channel [{}]", channel), e);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("SSL Peer did not present a certificate on channel [{}]", channel);
|
||||
}
|
||||
static void extactClientCertificates(Logger logger, ThreadContext threadContext, SSLEngine sslEngine, Object channel) {
|
||||
try {
|
||||
Certificate[] certs = sslEngine.getSession().getPeerCertificates();
|
||||
if (certs instanceof X509Certificate[]) {
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// this happens when client authentication is optional and the client does not provide credentials. If client
|
||||
// authentication was required then this connection should be closed before ever getting into this class
|
||||
assert sslEngine.getNeedClientAuth() == false;
|
||||
assert sslEngine.getWantClientAuth();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"SSL Peer did not present a certificate on channel [{}]", channel), e);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("SSL Peer did not present a certificate on channel [{}]", channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package org.elasticsearch.xpack.security.transport.filter;
|
||||
|
||||
|
||||
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.lucene.util.SetOnce;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
|
@ -22,6 +23,7 @@ import org.elasticsearch.transport.TransportSettings;
|
|||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -76,19 +78,15 @@ public class IPFilter {
|
|||
.immutableMap();
|
||||
|
||||
public static final SecurityIpFilterRule DEFAULT_PROFILE_ACCEPT_ALL = new SecurityIpFilterRule(true, "default:accept_all") {
|
||||
|
||||
@Override
|
||||
public boolean contains(InetAddress inetAddress) {
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowRule() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenyRule() {
|
||||
return false;
|
||||
public IpFilterRuleType ruleType() {
|
||||
return IpFilterRuleType.ACCEPT;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -179,7 +177,7 @@ public class IPFilter {
|
|||
updateRules();
|
||||
}
|
||||
|
||||
public boolean accept(String profile, InetAddress peerAddress) {
|
||||
public boolean accept(String profile, InetSocketAddress peerAddress) {
|
||||
if (licenseState.isIpFilteringAllowed() == false) {
|
||||
return true;
|
||||
}
|
||||
|
@ -190,18 +188,18 @@ public class IPFilter {
|
|||
}
|
||||
|
||||
for (SecurityIpFilterRule rule : rules.get(profile)) {
|
||||
if (rule.contains(peerAddress)) {
|
||||
boolean isAllowed = rule.isAllowRule();
|
||||
if (rule.matches(peerAddress)) {
|
||||
boolean isAllowed = rule.ruleType() == IpFilterRuleType.ACCEPT;
|
||||
if (isAllowed) {
|
||||
auditTrail.connectionGranted(peerAddress, profile, rule);
|
||||
auditTrail.connectionGranted(peerAddress.getAddress(), profile, rule);
|
||||
} else {
|
||||
auditTrail.connectionDenied(peerAddress, profile, rule);
|
||||
auditTrail.connectionDenied(peerAddress.getAddress(), profile, rule);
|
||||
}
|
||||
return isAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
auditTrail.connectionGranted(peerAddress, profile, DEFAULT_PROFILE_ACCEPT_ALL);
|
||||
auditTrail.connectionGranted(peerAddress.getAddress(), profile, DEFAULT_PROFILE_ACCEPT_ALL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.filter;
|
||||
|
||||
import io.netty.handler.ipfilter.IpFilterRule;
|
||||
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.network.NetworkAddress;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The Class PatternRule represents an IP filter rule using string patterns.
|
||||
* <br>
|
||||
* Rule Syntax:
|
||||
* <br>
|
||||
* <pre>
|
||||
* Rule ::= [n|i]:address n stands for computer name, i for ip address
|
||||
* address ::= <regex> | localhost
|
||||
* regex is a regular expression with '*' as multi character and '?' as single character wild card
|
||||
* </pre>
|
||||
* <br>
|
||||
* Example: allow localhost:
|
||||
* <br>
|
||||
* new PatternRule(true, "n:localhost")
|
||||
* <br>
|
||||
* Example: allow local lan:
|
||||
* <br>
|
||||
* new PatternRule(true, "i:192.168.0.*")
|
||||
* <br>
|
||||
* Example: block all
|
||||
* <br>
|
||||
* new PatternRule(false, "n:*")
|
||||
* <br>
|
||||
*/
|
||||
// this has been adopted from Netty3 there is no replacement in netty4 for this.
|
||||
final class PatternRule implements IpFilterRule {
|
||||
|
||||
private final Pattern ipPattern;
|
||||
private final Pattern namePattern;
|
||||
private final IpFilterRuleType ruleType;
|
||||
private final boolean localhost;
|
||||
private final String pattern;
|
||||
|
||||
/**
|
||||
* Instantiates a new pattern rule.
|
||||
*
|
||||
* @param ruleType indicates if this is an allow or block rule
|
||||
* @param pattern the filter pattern
|
||||
*/
|
||||
PatternRule(IpFilterRuleType ruleType, String pattern) {
|
||||
this.ruleType = ruleType;
|
||||
this.pattern = pattern;
|
||||
Pattern namePattern = null;
|
||||
Pattern ipPattern = null;
|
||||
boolean localhost = false;
|
||||
if (pattern != null) {
|
||||
String[] acls = pattern.split(",");
|
||||
String ip = "";
|
||||
String name = "";
|
||||
for (String c : acls) {
|
||||
c = c.trim();
|
||||
if ("n:localhost".equals(c)) {
|
||||
localhost = true;
|
||||
} else if (c.startsWith("n:")) {
|
||||
name = addRule(name, c.substring(2));
|
||||
} else if (c.startsWith("i:")) {
|
||||
ip = addRule(ip, c.substring(2));
|
||||
}
|
||||
}
|
||||
if (ip.length() != 0) {
|
||||
ipPattern = Pattern.compile(ip);
|
||||
}
|
||||
if (name.length() != 0) {
|
||||
namePattern = Pattern.compile(name);
|
||||
}
|
||||
}
|
||||
this.ipPattern = ipPattern;
|
||||
this.namePattern = namePattern;
|
||||
this.localhost = localhost;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the pattern.
|
||||
*
|
||||
* @return the pattern
|
||||
*/
|
||||
String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static String addRule(String pattern, String rule) {
|
||||
if (rule == null || rule.length() == 0) {
|
||||
return pattern;
|
||||
}
|
||||
if (pattern.length() != 0) {
|
||||
pattern += "|";
|
||||
}
|
||||
rule = rule.replaceAll("\\.", "\\\\.");
|
||||
rule = rule.replaceAll("\\*", ".*");
|
||||
rule = rule.replaceAll("\\?", ".");
|
||||
pattern += '(' + rule + ')';
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private boolean isLocalhost(InetAddress address) {
|
||||
try {
|
||||
return address.isAnyLocalAddress() || address.isLoopbackAddress() || NetworkInterface.getByInetAddress(address) != null;
|
||||
} catch (SocketException e) {
|
||||
// not defined - ie. it's not a local address
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
InetAddress inetAddress = remoteAddress.getAddress();
|
||||
if (localhost) {
|
||||
if (isLocalhost(inetAddress)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (ipPattern != null) {
|
||||
String format = NetworkAddress.format(inetAddress);
|
||||
if (ipPattern.matcher(format).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return checkHostName(inetAddress);
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "we compare the hostname of the address this is how netty3 did it and we keep it for BWC")
|
||||
private boolean checkHostName(InetAddress address) {
|
||||
if (namePattern != null) {
|
||||
if (namePattern.matcher(address.getHostName()).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return ruleType;
|
||||
}
|
||||
|
||||
boolean isLocalhost() {
|
||||
return localhost;
|
||||
}
|
||||
}
|
|
@ -5,17 +5,24 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.transport.filter;
|
||||
|
||||
import io.netty.handler.ipfilter.IpFilterRule;
|
||||
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||
import io.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.network.InetAddresses;
|
||||
import org.elasticsearch.common.network.NetworkAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.jboss.netty.handler.ipfilter.IpFilterRule;
|
||||
import org.jboss.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||
import org.jboss.netty.handler.ipfilter.PatternRule;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* decorator class to have a useful toString() method for an IpFilterRule
|
||||
|
@ -25,36 +32,25 @@ public class SecurityIpFilterRule implements IpFilterRule {
|
|||
|
||||
public static final SecurityIpFilterRule ACCEPT_ALL = new SecurityIpFilterRule(true, "accept_all") {
|
||||
@Override
|
||||
public boolean contains(InetAddress inetAddress) {
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowRule() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenyRule() {
|
||||
return false;
|
||||
public IpFilterRuleType ruleType() {
|
||||
return IpFilterRuleType.ACCEPT;
|
||||
}
|
||||
};
|
||||
|
||||
public static final SecurityIpFilterRule DENY_ALL = new SecurityIpFilterRule(true, "deny_all") {
|
||||
|
||||
@Override
|
||||
public boolean contains(InetAddress inetAddress) {
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowRule() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenyRule() {
|
||||
return true;
|
||||
public IpFilterRuleType ruleType() {
|
||||
return IpFilterRuleType.REJECT;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -71,25 +67,10 @@ public class SecurityIpFilterRule implements IpFilterRule {
|
|||
this.ipFilterRule = getRule(isAllowRule, ruleSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(InetAddress inetAddress) {
|
||||
return ipFilterRule.contains(inetAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowRule() {
|
||||
return ipFilterRule.isAllowRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenyRule() {
|
||||
return ipFilterRule.isDenyRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (isAllowRule()) {
|
||||
if (ruleType() == IpFilterRuleType.ACCEPT) {
|
||||
builder.append("allow ");
|
||||
} else {
|
||||
builder.append("deny ");
|
||||
|
@ -99,7 +80,76 @@ public class SecurityIpFilterRule implements IpFilterRule {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
static Tuple<InetAddress, Integer> parseSubnetMask(String address) throws UnknownHostException {
|
||||
int p = address.indexOf('/');
|
||||
if (p < 0) {
|
||||
throw new UnknownHostException("Invalid CIDR notation used: " + address);
|
||||
}
|
||||
if (p == address.length() -1) {
|
||||
throw new IllegalArgumentException("address must not end with a '/");
|
||||
}
|
||||
String addrString = address.substring(0, p);
|
||||
String maskString = address.substring(p + 1);
|
||||
InetAddress addr = InetAddress.getByName(addrString);
|
||||
int mask;
|
||||
if (maskString.indexOf('.') < 0) {
|
||||
mask = parseInt(maskString, -1);
|
||||
} else {
|
||||
mask = getNetMask(maskString);
|
||||
if (addr instanceof Inet6Address) {
|
||||
mask += 96;
|
||||
}
|
||||
}
|
||||
if (mask < 0) {
|
||||
throw new UnknownHostException("Invalid mask length used: " + maskString);
|
||||
}
|
||||
return new Tuple<>(addr, mask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Subnet's Netmask in Decimal format.<BR>
|
||||
* i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask
|
||||
*
|
||||
* @param netMask a network mask
|
||||
* @return the integer CIDR mask
|
||||
*/
|
||||
private static int getNetMask(String netMask) {
|
||||
StringTokenizer nm = new StringTokenizer(netMask, ".");
|
||||
int i = 0;
|
||||
int[] netmask = new int[4];
|
||||
while (nm.hasMoreTokens()) {
|
||||
netmask[i] = Integer.parseInt(nm.nextToken());
|
||||
i++;
|
||||
}
|
||||
int mask1 = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
mask1 += Integer.bitCount(netmask[i]);
|
||||
}
|
||||
return mask1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param intstr a string containing an integer.
|
||||
* @param def the default if the string does not contain a valid
|
||||
* integer.
|
||||
* @return the inetAddress from the integer
|
||||
*/
|
||||
private static int parseInt(String intstr, int def) {
|
||||
Integer res;
|
||||
if (intstr == null) {
|
||||
return def;
|
||||
}
|
||||
try {
|
||||
res = Integer.decode(intstr);
|
||||
} catch (Exception e) {
|
||||
res = def;
|
||||
}
|
||||
return res.intValue();
|
||||
}
|
||||
|
||||
static IpFilterRule getRule(boolean isAllowRule, String value) {
|
||||
IpFilterRuleType filterRuleType = isAllowRule ? IpFilterRuleType.ACCEPT : IpFilterRuleType.REJECT;
|
||||
String[] values = value.split(",");
|
||||
int allRuleIndex = Arrays.binarySearch(values, 0, values.length, "_all");
|
||||
if (allRuleIndex >= 0) {
|
||||
|
@ -111,36 +161,34 @@ public class SecurityIpFilterRule implements IpFilterRule {
|
|||
}
|
||||
|
||||
if (value.contains("/")) {
|
||||
// subnet rule...
|
||||
if (values.length != 1) {
|
||||
throw new IllegalArgumentException("multiple subnet filters cannot be specified in a single rule!");
|
||||
}
|
||||
try {
|
||||
return new IpSubnetFilterRule(isAllowRule, value);
|
||||
Tuple<InetAddress, Integer> inetAddressIntegerTuple = parseSubnetMask(value);
|
||||
return new IpSubnetFilterRule(inetAddressIntegerTuple.v1(), inetAddressIntegerTuple.v2(), filterRuleType);
|
||||
} catch (UnknownHostException e) {
|
||||
String ruleType = (isAllowRule ? "allow " : "deny ");
|
||||
throw new ElasticsearchException("unable to create ip filter for rule [" + ruleType + " " + value + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean firstAdded = false;
|
||||
StringBuilder ruleSpec = new StringBuilder();
|
||||
for (String singleValue : values) {
|
||||
if (firstAdded) {
|
||||
ruleSpec.append(",");
|
||||
} else {
|
||||
firstAdded = true;
|
||||
} else {
|
||||
// pattern rule - not netmask
|
||||
StringJoiner rules = new StringJoiner(",");
|
||||
for (String pattern : values) {
|
||||
if (InetAddresses.isInetAddress(pattern)) {
|
||||
// we want the inet addresses to be normalized especially in the IPv6 case where :0:0: is equivalent to ::
|
||||
// that's why we convert the address here and then format since PatternRule also uses the formatting to normalize
|
||||
// the value we are matching against
|
||||
InetAddress inetAddress = InetAddresses.forString(pattern);
|
||||
pattern = "i:" + NetworkAddress.format(inetAddress);
|
||||
} else {
|
||||
pattern = "n:" + pattern;
|
||||
}
|
||||
rules.add(pattern);
|
||||
}
|
||||
|
||||
boolean isInetAddress = InetAddresses.isInetAddress(singleValue);
|
||||
if (isInetAddress) {
|
||||
ruleSpec.append("i:");
|
||||
} else {
|
||||
ruleSpec.append("n:");
|
||||
}
|
||||
ruleSpec.append(singleValue);
|
||||
return new PatternRule(filterRuleType, rules.toString());
|
||||
}
|
||||
|
||||
return new PatternRule(isAllowRule, ruleSpec.toString());
|
||||
}
|
||||
|
||||
static String getRuleSpec(TransportAddress... addresses) {
|
||||
|
@ -157,4 +205,14 @@ public class SecurityIpFilterRule implements IpFilterRule {
|
|||
}
|
||||
return ruleSpec.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InetSocketAddress remoteAddress) {
|
||||
return ipFilterRule.matches(remoteAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpFilterRuleType ruleType() {
|
||||
return ipFilterRule.ruleType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.jboss.netty.channel.ChannelEvent;
|
||||
import org.jboss.netty.channel.ChannelHandler;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.handler.ipfilter.IpFilteringHandlerImpl;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class IPFilterNetty3UpstreamHandler extends IpFilteringHandlerImpl {
|
||||
|
||||
private final IPFilter filter;
|
||||
private final String profile;
|
||||
|
||||
public IPFilterNetty3UpstreamHandler(IPFilter filter, String profile) {
|
||||
this.filter = filter;
|
||||
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 filter.accept(profile, inetSocketAddress.getAddress());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
import org.jboss.netty.channel.ChannelFutureListener;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.DownstreamMessageEvent;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* Netty requires that nothing be written to the channel prior to the handshake. Writing before the handshake
|
||||
* completes, results in odd SSLExceptions being thrown. Channel writes can happen from any thread that
|
||||
* can access the channel and Netty does not provide a way to ensure the handshake has occurred before the
|
||||
* application writes to the channel. This handler will queue up writes until the handshake has occurred and
|
||||
* then will pass the writes through the pipeline. After all writes have been completed, this handler removes
|
||||
* itself from the pipeline.
|
||||
*
|
||||
* NOTE: This class assumes that the transport will not use a closed channel again or attempt to reconnect, which
|
||||
* is the way that Netty3Transport currently works
|
||||
*/
|
||||
public class Netty3HandshakeWaitingHandler extends SimpleChannelHandler {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
private boolean handshaken = false;
|
||||
private Queue<MessageEvent> pendingWrites = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* @param logger We pass a context aware logger here (logger that is aware of the node name & env)
|
||||
*/
|
||||
public Netty3HandshakeWaitingHandler(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelConnected(final ChannelHandlerContext ctx, final ChannelStateEvent e) throws Exception {
|
||||
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
|
||||
|
||||
final ChannelFuture handshakeFuture = sslHandler.handshake();
|
||||
handshakeFuture.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture channelFuture) throws Exception {
|
||||
if (handshakeFuture.isSuccess()) {
|
||||
logger.debug("SSL/TLS handshake completed for channel");
|
||||
|
||||
// We synchronize here to allow all pending writes to be processed prior to any writes coming from
|
||||
// another thread
|
||||
synchronized (Netty3HandshakeWaitingHandler.this) {
|
||||
handshaken = true;
|
||||
while (!pendingWrites.isEmpty()) {
|
||||
MessageEvent event = pendingWrites.remove();
|
||||
ctx.sendDownstream(event);
|
||||
}
|
||||
ctx.getPipeline().remove(Netty3HandshakeWaitingHandler.class);
|
||||
}
|
||||
|
||||
ctx.sendUpstream(e);
|
||||
} else {
|
||||
Throwable cause = handshakeFuture.getCause();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"SSL/TLS handshake failed, closing channel: {}", cause.getMessage()), cause);
|
||||
} else {
|
||||
logger.error("SSL/TLS handshake failed, closing channel: {}", cause.getMessage());
|
||||
}
|
||||
|
||||
synchronized (Netty3HandshakeWaitingHandler.this) {
|
||||
// Set failure on the futures of each message so that listeners are called
|
||||
while (!pendingWrites.isEmpty()) {
|
||||
DownstreamMessageEvent event = (DownstreamMessageEvent) pendingWrites.remove();
|
||||
event.getFuture().setFailure(cause);
|
||||
}
|
||||
|
||||
// Some writes may be waiting to acquire lock, if so the SetFailureOnAddQueue will set
|
||||
// failure on their futures
|
||||
pendingWrites = new SetFailureOnAddQueue(cause);
|
||||
handshakeFuture.getChannel().close();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
// Writes can come from any thread so we need to ensure that we do not let any through
|
||||
// until handshake has completed
|
||||
if (!handshaken) {
|
||||
pendingWrites.add(e);
|
||||
return;
|
||||
}
|
||||
ctx.sendDownstream(e);
|
||||
}
|
||||
|
||||
synchronized boolean hasPendingWrites() {
|
||||
return !pendingWrites.isEmpty();
|
||||
}
|
||||
|
||||
private static class SetFailureOnAddQueue extends LinkedList<MessageEvent> {
|
||||
private final Throwable cause;
|
||||
|
||||
SetFailureOnAddQueue(Throwable cause) {
|
||||
super();
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(MessageEvent messageEvent) {
|
||||
DownstreamMessageEvent event = (DownstreamMessageEvent) messageEvent;
|
||||
event.getFuture().setFailure(cause);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.http.netty3.Netty3HttpServerTransport;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||
import org.jboss.netty.channel.ExceptionEvent;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_COMPRESSION;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
|
||||
public class SecurityNetty3HttpServerTransport extends Netty3HttpServerTransport {
|
||||
|
||||
private final IPFilter ipFilter;
|
||||
private final SSLService sslService;
|
||||
private final boolean ssl;
|
||||
|
||||
public SecurityNetty3HttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter,
|
||||
SSLService sslService, ThreadPool threadPool) {
|
||||
super(settings, networkService, bigArrays, threadPool);
|
||||
this.ipFilter = ipFilter;
|
||||
this.sslService = sslService;
|
||||
this.ssl = HTTP_SSL_ENABLED.get(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
|
||||
if (!lifecycle.started()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Throwable t = e.getCause();
|
||||
if (isNotSslRecordException(t)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"received plaintext http traffic on a https channel, closing connection {}",
|
||||
ctx.getChannel()),
|
||||
t);
|
||||
} else {
|
||||
logger.warn("received plaintext http traffic on a https channel, closing connection {}", ctx.getChannel());
|
||||
}
|
||||
ctx.getChannel().close();
|
||||
} else if (isCloseDuringHandshakeException(t)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace((Supplier<?>) () -> new ParameterizedMessage("connection {} closed during handshake", ctx.getChannel()), t);
|
||||
} else {
|
||||
logger.warn("connection {} closed during handshake", ctx.getChannel());
|
||||
}
|
||||
ctx.getChannel().close();
|
||||
} else {
|
||||
super.exceptionCaught(ctx, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
ipFilter.setBoundHttpTransportAddress(this.boundAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipelineFactory configureServerChannelPipelineFactory() {
|
||||
return new HttpSslChannelPipelineFactory(this);
|
||||
}
|
||||
|
||||
private class HttpSslChannelPipelineFactory extends HttpChannelPipelineFactory {
|
||||
|
||||
private final Settings sslSettings;
|
||||
|
||||
public HttpSslChannelPipelineFactory(Netty3HttpServerTransport transport) {
|
||||
super(transport, detailedErrorsEnabled, threadPool.getThreadContext());
|
||||
this.sslSettings = SSLService.getHttpTransportSSLSettings(settings);
|
||||
if (ssl && sslService.isConfigurationValidForServerUsage(sslSettings, Settings.EMPTY) == false) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the " +
|
||||
"[xpack.security.http.ssl.key] or [xpack.security.http.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (ssl) {
|
||||
SSLEngine engine = sslService.createSSLEngine(sslSettings, Settings.EMPTY);
|
||||
pipeline.addFirst("ssl", new SslHandler(engine));
|
||||
}
|
||||
pipeline.addFirst("ipfilter", new IPFilterNetty3UpstreamHandler(ipFilter, IPFilter.HTTP_PROFILE_NAME));
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
public static void overrideSettings(Settings.Builder settingsBuilder, Settings settings) {
|
||||
if (HTTP_SSL_ENABLED.get(settings) && SETTING_HTTP_COMPRESSION.exists(settings) == false) {
|
||||
settingsBuilder.put(SETTING_HTTP_COMPRESSION.getKey(), false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.logging.log4j.util.Supplier;
|
||||
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.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty3.Netty3Transport;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||
import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.xpack.security.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
||||
|
||||
public class SecurityNetty3Transport extends Netty3Transport {
|
||||
|
||||
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 SecurityNetty3Transport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays,
|
||||
@Nullable IPFilter authenticator, SSLService sslService, NamedWriteableRegistry namedWriteableRegistry,
|
||||
CircuitBreakerService circuitBreakerService) {
|
||||
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."));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
if (authenticator != null) {
|
||||
authenticator.setBoundTransportAddress(boundAddress(), profileBoundAddresses());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipelineFactory configureClientChannelPipelineFactory() {
|
||||
return new SslClientChannelPipelineFactory(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipelineFactory configureServerChannelPipelineFactory(String name, Settings profileSettings) {
|
||||
return new SslServerChannelPipelineFactory(this, name, settings, profileSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Channel channel, Exception e) throws IOException {
|
||||
if (isNotSslRecordException(e)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(
|
||||
(Supplier<?>) () -> new ParameterizedMessage(
|
||||
"received plaintext traffic on a encrypted channel, closing connection {}", channel), e);
|
||||
} else {
|
||||
logger.warn("received plaintext traffic on a encrypted channel, closing connection {}", channel);
|
||||
}
|
||||
disconnectFromNodeChannel(channel, e);
|
||||
} else if (isCloseDuringHandshakeException(e)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace((Supplier<?>) () -> new ParameterizedMessage("connection {} closed during handshake", channel), e);
|
||||
} else {
|
||||
logger.warn("connection {} closed during handshake", channel);
|
||||
}
|
||||
disconnectFromNodeChannel(channel, e);
|
||||
} else {
|
||||
super.onException(channel, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Settings profileSslSettings(Settings profileSettings) {
|
||||
return profileSettings.getByPrefix(setting("ssl."));
|
||||
}
|
||||
|
||||
private class SslServerChannelPipelineFactory extends ServerChannelPipelineFactory {
|
||||
|
||||
private final boolean profileSsl;
|
||||
private final Settings profileSslSettings;
|
||||
|
||||
SslServerChannelPipelineFactory(Netty3Transport nettyTransport, String name, Settings settings, Settings profileSettings) {
|
||||
super(nettyTransport, name, settings);
|
||||
this.profileSsl = PROFILE_SSL_SETTING.exists(profileSettings) ? PROFILE_SSL_SETTING.get(profileSettings) : ssl;
|
||||
this.profileSslSettings = profileSslSettings(profileSettings);
|
||||
if (profileSsl && sslService.isConfigurationValidForServerUsage(profileSslSettings, transportSSLSettings) == false) {
|
||||
if (TransportSettings.DEFAULT_PROFILE.equals(name)) {
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[xpack.security.transport.ssl.key] or [xpack.security.transport.ssl.keystore.path] setting");
|
||||
}
|
||||
throw new IllegalArgumentException("a key must be provided to run as a server. the key should be configured using the "
|
||||
+ "[transport.profiles." + name + ".xpack.security.ssl.key] or [transport.profiles." + name
|
||||
+ ".xpack.security.ssl.keystore.path] setting");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (profileSsl) {
|
||||
final SSLEngine serverEngine = sslService.createSSLEngine(profileSslSettings, transportSSLSettings);
|
||||
serverEngine.setUseClientMode(false);
|
||||
pipeline.addFirst("ssl", new SslHandler(serverEngine));
|
||||
}
|
||||
if (authenticator != null) {
|
||||
pipeline.addFirst("ipfilter", new IPFilterNetty3UpstreamHandler(authenticator, name));
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
private class SslClientChannelPipelineFactory extends ClientChannelPipelineFactory {
|
||||
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
|
||||
SslClientChannelPipelineFactory(Netty3Transport transport) {
|
||||
super(transport);
|
||||
this.hostnameVerificationEnabled =
|
||||
sslService.getVerificationMode(transportSSLSettings, Settings.EMPTY).isHostnameVerificationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (ssl) {
|
||||
pipeline.addFirst("sslInitializer", new ClientSslHandlerInitializer());
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler that waits until connect is called to create a SSLEngine with the proper parameters in order to
|
||||
* perform hostname verification
|
||||
*/
|
||||
private class ClientSslHandlerInitializer extends SimpleChannelHandler {
|
||||
|
||||
@Override
|
||||
public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) {
|
||||
SSLEngine sslEngine;
|
||||
if (hostnameVerificationEnabled) {
|
||||
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();
|
||||
// we create the socket based on the name given. don't reverse DNS
|
||||
sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY, inetSocketAddress.getHostString(),
|
||||
inetSocketAddress.getPort());
|
||||
} else {
|
||||
sslEngine = sslService.createSSLEngine(transportSSLSettings, Settings.EMPTY);
|
||||
}
|
||||
|
||||
sslEngine.setUseClientMode(true);
|
||||
ctx.getPipeline().replace(this, "ssl", new SslHandler(sslEngine));
|
||||
ctx.getPipeline().addAfter("ssl", "handshake", new Netty3HandshakeWaitingHandler(logger));
|
||||
|
||||
ctx.sendDownstream(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ class IpFilterRemoteAddressFilter extends AbstractRemoteAddressFilter<InetSocket
|
|||
@Override
|
||||
protected boolean accept(final ChannelHandlerContext ctx, final InetSocketAddress remoteAddress) throws Exception {
|
||||
// at this stage no auth has happened, so we do not have any principal anyway
|
||||
return filter.accept(profile, remoteAddress.getAddress());
|
||||
return filter.accept(profile, remoteAddress);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import static org.elasticsearch.xpack.XPackSettings.TRANSPORT_SSL_ENABLED;
|
|||
*/
|
||||
public class SecurityNetty4Transport extends Netty4Transport {
|
||||
|
||||
private static final Setting<Boolean> PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false);
|
||||
public static final Setting<Boolean> PROFILE_SSL_SETTING = Setting.boolSetting(setting("ssl.enabled"), false);
|
||||
|
||||
private final SSLService sslService;
|
||||
@Nullable private final IPFilter authenticator;
|
||||
|
@ -157,4 +157,9 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
super.connect(ctx, remoteAddress, localAddress, promise);
|
||||
}
|
||||
}
|
||||
|
||||
public static Settings profileSslSettings(Settings profileSettings) {
|
||||
return profileSettings.getByPrefix(setting("ssl."));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.http.netty3;
|
||||
|
||||
import org.elasticsearch.transport.netty3.Netty3OpenChannelsHandler;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/** Allows setting a mock into Netty3HttpServerTransport */
|
||||
public class Netty3HttpMockUtil {
|
||||
|
||||
/**
|
||||
* We don't really need to start Netty for these tests, but we can't create a pipeline
|
||||
* with a null handler. So we set it to a mock for tests.
|
||||
*/
|
||||
public static void setOpenChannelsHandlerToMock(Netty3HttpServerTransport transport) throws Exception {
|
||||
transport.serverOpenChannels = mock(Netty3OpenChannelsHandler.class);
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ import org.elasticsearch.common.network.NetworkModule;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
|
@ -138,7 +137,6 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.elasticsearch.common.unit.TimeValue;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
||||
|
@ -48,7 +47,7 @@ public class LicenseServiceClusterTests extends AbstractLicensesIntegrationTestC
|
|||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
return Arrays.asList(XPackPlugin.class, Netty3Plugin.class, Netty4Plugin.class);
|
||||
return Arrays.asList(XPackPlugin.class, Netty4Plugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.license;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
|
@ -29,7 +30,6 @@ import org.elasticsearch.plugins.Plugin;
|
|||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
@ -108,7 +108,6 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase.Scope;
|
||||
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
|
@ -151,7 +150,8 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
|
||||
@Override
|
||||
public Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
return Arrays.asList(xpackPluginClass(), Netty3Plugin.class, Netty4Plugin.class);
|
||||
return Arrays.asList(xpackPluginClass(),
|
||||
Netty4Plugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.transport.netty3;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/** Allows setting a mock into Netty3Transport */
|
||||
public class Netty3MockUtil {
|
||||
/**
|
||||
* We don't really need to start Netty for these tests, but we can't create a pipeline
|
||||
* with a null handler. So we set it to a mock for tests.
|
||||
*/
|
||||
public static void setOpenChannelsHandlerToMock(Netty3Transport transport) throws Exception {
|
||||
transport.serverOpenChannels = mock(Netty3OpenChannelsHandler.class);
|
||||
}
|
||||
}
|
|
@ -5,9 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.transport.netty4;
|
||||
|
||||
import org.elasticsearch.transport.netty3.Netty3OpenChannelsHandler;
|
||||
import org.elasticsearch.transport.netty3.Netty3Transport;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/** Allows setting a mock into Netty3Transport */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.common.http;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
|
@ -18,7 +19,6 @@ import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth;
|
|||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
|
@ -48,7 +48,6 @@ public class MonitoringSettingsIntegTests extends MonitoringIntegTestCase {
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.elasticsearch.common.network.NetworkModule;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
|
||||
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
|
||||
|
@ -20,6 +19,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue;
|
||||
|
@ -51,7 +51,6 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase {
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.monitoring.test;
|
||||
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
|
@ -42,7 +43,6 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
|||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.watcher.WatcherLifeCycleService;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.jboss.netty.util.internal.SystemPropertyUtil;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
|
|
|
@ -149,29 +149,6 @@ public class SecurityTests extends ESTestCase {
|
|||
assertEquals(Security.NAME4, NetworkModule.HTTP_TYPE_SETTING.get(defaultSettings));
|
||||
}
|
||||
|
||||
public void testTransportSettingNetty3Transport() {
|
||||
Settings baseSettings = Settings.builder().put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3).build();
|
||||
Settings transport3 = Security.additionalSettings(baseSettings, false);
|
||||
assertFalse(NetworkModule.TRANSPORT_TYPE_SETTING.exists(transport3));
|
||||
assertEquals(Security.NAME4, NetworkModule.HTTP_TYPE_SETTING.get(transport3));
|
||||
}
|
||||
|
||||
public void testTransportSettingNetty3Http() {
|
||||
Settings baseSettings = Settings.builder().put(NetworkModule.HTTP_TYPE_KEY, Security.NAME3).build();
|
||||
Settings http3 = Security.additionalSettings(baseSettings, false);
|
||||
assertEquals(Security.NAME4, NetworkModule.TRANSPORT_TYPE_SETTING.get(http3));
|
||||
assertFalse(NetworkModule.HTTP_TYPE_SETTING.exists(http3));
|
||||
}
|
||||
|
||||
public void testTransportSettingNetty3Both() {
|
||||
Settings both3 = Security.additionalSettings(Settings.builder()
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3)
|
||||
.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME3)
|
||||
.build(), false);
|
||||
assertFalse(NetworkModule.TRANSPORT_TYPE_SETTING.exists(both3));
|
||||
assertFalse(NetworkModule.HTTP_TYPE_SETTING.exists(both3));
|
||||
}
|
||||
|
||||
public void testTransportSettingNetty4Both() {
|
||||
Settings both4 = Security.additionalSettings(Settings.builder()
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4)
|
||||
|
@ -182,18 +159,16 @@ public class SecurityTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testTransportSettingValidation() {
|
||||
final String badType = randomFrom("netty3", "netty4", "other", "security1");
|
||||
final String badType = randomFrom("netty4", "other", "security1");
|
||||
Settings settingsTransport = Settings.builder().put(NetworkModule.TRANSPORT_TYPE_KEY, badType).build();
|
||||
IllegalArgumentException badTransport = expectThrows(IllegalArgumentException.class,
|
||||
() -> Security.additionalSettings(settingsTransport, false));
|
||||
assertThat(badTransport.getMessage(), containsString(Security.NAME3));
|
||||
assertThat(badTransport.getMessage(), containsString(Security.NAME4));
|
||||
assertThat(badTransport.getMessage(), containsString(NetworkModule.TRANSPORT_TYPE_KEY));
|
||||
|
||||
Settings settingsHttp = Settings.builder().put(NetworkModule.HTTP_TYPE_KEY, badType).build();
|
||||
IllegalArgumentException badHttp = expectThrows(IllegalArgumentException.class,
|
||||
() -> Security.additionalSettings(settingsHttp, false));
|
||||
assertThat(badHttp.getMessage(), containsString(Security.NAME3));
|
||||
assertThat(badHttp.getMessage(), containsString(Security.NAME4));
|
||||
assertThat(badHttp.getMessage(), containsString(NetworkModule.HTTP_TYPE_KEY));
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.elasticsearch.test.SecuritySettingsSource;
|
|||
import org.elasticsearch.xpack.security.SecurityTemplateService;
|
||||
import org.elasticsearch.xpack.security.authz.permission.FieldPermissions;
|
||||
import org.elasticsearch.xpack.security.client.SecurityClient;
|
||||
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.Before;
|
|||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -223,7 +224,7 @@ public class IPFilterTests extends ESTestCase {
|
|||
// don't use the assert helper because we don't want the audit trail to be invoked here
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be allowed", "8.8.8.8");
|
||||
InetAddress address = InetAddresses.forString("8.8.8.8");
|
||||
assertThat(message, ipFilter.accept("default", address), is(true));
|
||||
assertThat(message, ipFilter.accept("default", new InetSocketAddress(address, 0)), is(true));
|
||||
verifyZeroInteractions(auditTrail);
|
||||
|
||||
// for sanity enable license and check that it is denied
|
||||
|
@ -249,7 +250,7 @@ public class IPFilterTests extends ESTestCase {
|
|||
for (String inetAddress : inetAddresses) {
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be allowed", inetAddress);
|
||||
InetAddress address = InetAddresses.forString(inetAddress);
|
||||
assertThat(message, ipFilter.accept(profile, address), is(true));
|
||||
assertTrue(message, ipFilter.accept(profile, new InetSocketAddress(address, 0)));
|
||||
ArgumentCaptor<SecurityIpFilterRule> ruleCaptor = ArgumentCaptor.forClass(SecurityIpFilterRule.class);
|
||||
verify(auditTrail).connectionGranted(eq(address), eq(profile), ruleCaptor.capture());
|
||||
assertNotNull(ruleCaptor.getValue());
|
||||
|
@ -264,7 +265,7 @@ public class IPFilterTests extends ESTestCase {
|
|||
for (String inetAddress : inetAddresses) {
|
||||
String message = String.format(Locale.ROOT, "Expected address %s to be denied", inetAddress);
|
||||
InetAddress address = InetAddresses.forString(inetAddress);
|
||||
assertThat(message, ipFilter.accept(profile, address), is(false));
|
||||
assertFalse(message, ipFilter.accept(profile, new InetSocketAddress(address, 0)));
|
||||
ArgumentCaptor<SecurityIpFilterRule> ruleCaptor = ArgumentCaptor.forClass(SecurityIpFilterRule.class);
|
||||
verify(auditTrail).connectionDenied(eq(address), eq(profile), ruleCaptor.capture());
|
||||
assertNotNull(ruleCaptor.getValue());
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.test.SecurityIntegTestCase;
|
|||
import org.junit.BeforeClass;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -162,7 +163,7 @@ public class IpFilteringUpdateTests extends SecurityIntegTestCase {
|
|||
|
||||
IPFilter ipFilter = internalCluster().getDataNodeInstance(IPFilter.class);
|
||||
String message = String.format(Locale.ROOT, "Expected allowed connection for profile %s against host %s", profile, host);
|
||||
assertThat(message, ipFilter.accept(profile, InetAddress.getByName(host)), is(true));
|
||||
assertThat(message, ipFilter.accept(profile, new InetSocketAddress(InetAddress.getByName(host), 0)), is(true));
|
||||
}
|
||||
|
||||
private void assertConnectionRejected(String profile, String host) throws UnknownHostException {
|
||||
|
@ -173,6 +174,6 @@ public class IpFilteringUpdateTests extends SecurityIntegTestCase {
|
|||
|
||||
IPFilter ipFilter = internalCluster().getDataNodeInstance(IPFilter.class);
|
||||
String message = String.format(Locale.ROOT, "Expected rejection for profile %s against host %s", profile, host);
|
||||
assertThat(message, ipFilter.accept(profile, InetAddress.getByName(host)), is(false));
|
||||
assertThat(message, ipFilter.accept(profile, new InetSocketAddress(InetAddress.getByName(host), 0)), is(false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.filter;
|
||||
|
||||
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class PatternRuleTests extends ESTestCase {
|
||||
|
||||
public void testSingleIpRule() throws UnknownHostException {
|
||||
PatternRule rule = new PatternRule(IpFilterRuleType.REJECT, "i:127.0.0.1");
|
||||
assertFalse(rule.isLocalhost());
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)));
|
||||
assertEquals(IpFilterRuleType.REJECT, rule.ruleType());
|
||||
|
||||
rule = new PatternRule(IpFilterRuleType.REJECT, "i:192.168.*");
|
||||
assertFalse(rule.isLocalhost());
|
||||
assertFalse(rule.matches(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("192.168.2.1"), 0)));
|
||||
assertEquals(IpFilterRuleType.REJECT, rule.ruleType());
|
||||
}
|
||||
|
||||
public void testSingleLocalHostRule() throws UnknownHostException {
|
||||
PatternRule rule = new PatternRule(IpFilterRuleType.ACCEPT, "n:localhost");
|
||||
assertTrue(rule.isLocalhost());
|
||||
assertTrue(rule.matches(new InetSocketAddress(getLocalHost(), 0)));
|
||||
assertEquals(IpFilterRuleType.ACCEPT, rule.ruleType());
|
||||
}
|
||||
|
||||
public void testMultiRules() throws UnknownHostException {
|
||||
PatternRule rule = new PatternRule(IpFilterRuleType.ACCEPT, "n:localhost,i:127.0.0.1,i:192.168.9.*");
|
||||
assertTrue(rule.isLocalhost());
|
||||
assertTrue(rule.matches(new InetSocketAddress(getLocalHost(), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("192.168.9.1"), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)));
|
||||
assertFalse(rule.matches(new InetSocketAddress(InetAddress.getByName("192.168.11.1"), 0)));
|
||||
assertEquals(IpFilterRuleType.ACCEPT, rule.ruleType());
|
||||
}
|
||||
|
||||
public void testAll() throws UnknownHostException {
|
||||
PatternRule rule = new PatternRule(IpFilterRuleType.ACCEPT, "n:*");
|
||||
assertFalse(rule.isLocalhost());
|
||||
assertTrue(rule.matches(new InetSocketAddress(getLocalHost(), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("192.168.9.1"), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)));
|
||||
assertTrue(rule.matches(new InetSocketAddress(InetAddress.getByName("192.168.11.1"), 0)));
|
||||
assertEquals(IpFilterRuleType.ACCEPT, rule.ruleType());
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "just for this test")
|
||||
private static InetAddress getLocalHost() throws UnknownHostException {
|
||||
return InetAddress.getLocalHost();
|
||||
}
|
||||
}
|
|
@ -5,15 +5,20 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.transport.filter;
|
||||
|
||||
import io.netty.handler.ipfilter.IpFilterRule;
|
||||
import io.netty.handler.ipfilter.IpFilterRuleType;
|
||||
import io.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.network.NetworkAddress;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.jboss.netty.handler.ipfilter.IpFilterRule;
|
||||
import org.jboss.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||
import org.jboss.netty.handler.ipfilter.PatternRule;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule.ACCEPT_ALL;
|
||||
import static org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule.DENY_ALL;
|
||||
import static org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule.getRule;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
||||
|
@ -43,9 +48,13 @@ public class SecurityIpFilterRuleTests extends ESTestCase {
|
|||
final boolean allow = randomBoolean();
|
||||
IpFilterRule rule = getRule(allow, "127.0.0.0/24");
|
||||
assertThat(rule, instanceOf(IpSubnetFilterRule.class));
|
||||
assertThat(rule.isAllowRule(), equalTo(allow));
|
||||
if (allow) {
|
||||
assertEquals(rule.ruleType(), IpFilterRuleType.ACCEPT);
|
||||
} else {
|
||||
assertEquals(rule.ruleType(), IpFilterRuleType.REJECT);
|
||||
}
|
||||
IpSubnetFilterRule ipSubnetFilterRule = (IpSubnetFilterRule) rule;
|
||||
assertThat(ipSubnetFilterRule.contains("127.0.0.1"), equalTo(true));
|
||||
assertTrue(ipSubnetFilterRule.matches(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0)));
|
||||
}
|
||||
|
||||
public void testParseIpSubnetFilterRuleWithOtherValues() throws Exception {
|
||||
|
@ -62,6 +71,27 @@ public class SecurityIpFilterRuleTests extends ESTestCase {
|
|||
String ruleSpec = "127.0.0.1,::1,192.168.0.*,name*,specific_name";
|
||||
IpFilterRule rule = getRule(allow, ruleSpec);
|
||||
assertThat(rule, instanceOf(PatternRule.class));
|
||||
assertThat(rule.isAllowRule(), equalTo(allow));
|
||||
if (allow) {
|
||||
assertEquals(rule.ruleType(), IpFilterRuleType.ACCEPT);
|
||||
} else {
|
||||
assertEquals(rule.ruleType(), IpFilterRuleType.REJECT);
|
||||
}
|
||||
}
|
||||
|
||||
public void testParseSubnetMask() throws UnknownHostException {
|
||||
Tuple<InetAddress, Integer> result = SecurityIpFilterRule.parseSubnetMask("2001:0db8:85a3:0000:0000:8a2e:0370:7334/24");
|
||||
assertEquals(NetworkAddress.format(result.v1()), "2001:db8:85a3::8a2e:370:7334");
|
||||
assertEquals(24, result.v2().intValue());
|
||||
|
||||
result = SecurityIpFilterRule.parseSubnetMask("127.0.0.0/24");
|
||||
assertEquals(NetworkAddress.format(result.v1()), "127.0.0.0");
|
||||
assertEquals(24, result.v2().intValue());
|
||||
|
||||
result = SecurityIpFilterRule.parseSubnetMask("127.0.0.1/255.255.255.0");
|
||||
assertEquals(NetworkAddress.format(result.v1()), "127.0.0.1");
|
||||
assertEquals(24, result.v2().intValue());
|
||||
|
||||
expectThrows(UnknownHostException.class, () -> SecurityIpFilterRule.parseSubnetMask("127.0.0.1"));
|
||||
expectThrows(IllegalArgumentException.class, () -> SecurityIpFilterRule.parseSubnetMask("127.0.0.1/"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.elasticsearch.common.component.Lifecycle;
|
||||
import org.elasticsearch.common.network.InetAddresses;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelConfig;
|
||||
import org.jboss.netty.channel.ChannelEvent;
|
||||
import org.jboss.netty.channel.ChannelFactory;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
import org.jboss.netty.channel.ChannelHandler;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jboss.netty.channel.UpstreamMessageEvent;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class IPFilterNetty3UpstreamHandlerTests extends ESTestCase {
|
||||
private IPFilterNetty3UpstreamHandler nettyUpstreamHandler;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.transport.filter.allow", "127.0.0.1")
|
||||
.put("xpack.security.transport.filter.deny", "10.0.0.0/8")
|
||||
.build();
|
||||
|
||||
boolean isHttpEnabled = randomBoolean();
|
||||
|
||||
Transport transport = mock(Transport.class);
|
||||
TransportAddress address = new TransportAddress(InetAddress.getLoopbackAddress(), 9300);
|
||||
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { address }, address));
|
||||
when(transport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
|
||||
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(
|
||||
IPFilter.HTTP_FILTER_ALLOW_SETTING,
|
||||
IPFilter.HTTP_FILTER_DENY_SETTING,
|
||||
IPFilter.IP_FILTER_ENABLED_HTTP_SETTING,
|
||||
IPFilter.IP_FILTER_ENABLED_SETTING,
|
||||
IPFilter.TRANSPORT_FILTER_ALLOW_SETTING,
|
||||
IPFilter.TRANSPORT_FILTER_DENY_SETTING,
|
||||
TransportSettings.TRANSPORT_PROFILES_SETTING)));
|
||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isIpFilteringAllowed()).thenReturn(true);
|
||||
AuditTrailService auditTrailService = new AuditTrailService(settings, Collections.emptyList(), licenseState);
|
||||
IPFilter ipFilter = new IPFilter(settings, auditTrailService, clusterSettings, licenseState);
|
||||
ipFilter.setBoundTransportAddress(transport.boundAddress(), transport.profileBoundAddresses());
|
||||
if (isHttpEnabled) {
|
||||
HttpServerTransport httpTransport = mock(HttpServerTransport.class);
|
||||
TransportAddress httpAddress = new TransportAddress(InetAddress.getLoopbackAddress(), 9200);
|
||||
when(httpTransport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { httpAddress }, httpAddress));
|
||||
when(httpTransport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
|
||||
ipFilter.setBoundHttpTransportAddress(httpTransport.boundAddress());
|
||||
}
|
||||
|
||||
if (isHttpEnabled) {
|
||||
nettyUpstreamHandler = new IPFilterNetty3UpstreamHandler(ipFilter, IPFilter.HTTP_PROFILE_NAME);
|
||||
} else {
|
||||
nettyUpstreamHandler = new IPFilterNetty3UpstreamHandler(ipFilter, "default");
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatFilteringWorksByIp() throws Exception {
|
||||
InetSocketAddress localhostAddr = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 12345);
|
||||
assertThat(nettyUpstreamHandler.accept(new NullChannelHandlerContext(), new UpstreamMessageEvent(
|
||||
new NullChannel(), "my message", localhostAddr), localhostAddr), is(true));
|
||||
|
||||
InetSocketAddress remoteAddr = new InetSocketAddress(InetAddresses.forString("10.0.0.8"), 12345);
|
||||
assertThat(nettyUpstreamHandler.accept(new NullChannelHandlerContext(), new UpstreamMessageEvent(
|
||||
new NullChannel(), "my message", remoteAddr), remoteAddr), is(false));
|
||||
}
|
||||
|
||||
private static class NullChannelHandlerContext implements ChannelHandlerContext {
|
||||
@Override
|
||||
public boolean canHandleDownstream() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandleUpstream() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttachment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler getHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDownstream(ChannelEvent e) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendUpstream(ChannelEvent e) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(Object attachment) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
|
||||
private static class NullChannel implements Channel {
|
||||
@Override
|
||||
public ChannelFuture bind(SocketAddress localAddress) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture close() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture connect(SocketAddress remoteAddress) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture disconnect() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture getCloseFuture() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelConfig getConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFactory getFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterestOps() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture setInterestOps(int interestOps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture setReadable(boolean readable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUserDefinedWritability(int i) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserDefinedWritability(int i, boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture unbind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture write(Object message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture write(Object message, SocketAddress remoteAddress) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Channel o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttachment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttachment(Object attachment) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||
import org.jboss.netty.channel.Channels;
|
||||
import org.jboss.netty.channel.ExceptionEvent;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
|
||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.BindException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class Netty3HandshakeWaitingHandlerTests extends ESTestCase {
|
||||
private static final int CONCURRENT_CLIENT_REQUESTS = 20;
|
||||
|
||||
private int iterations;
|
||||
private int randomPort;
|
||||
|
||||
private ServerBootstrap serverBootstrap;
|
||||
private ClientBootstrap clientBootstrap;
|
||||
private SSLService sslService;
|
||||
|
||||
private final AtomicReference<Throwable> failureCause = new AtomicReference<>();
|
||||
private ExecutorService threadPoolExecutor;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
randomPort = randomIntBetween(49000, 65500);
|
||||
iterations = randomIntBetween(10, 100);
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
sslService = new SSLService(settings, env);
|
||||
|
||||
startBootstrap();
|
||||
|
||||
clientBootstrap = new ClientBootstrap(new NioClientSocketChannelFactory());
|
||||
|
||||
threadPoolExecutor = Executors.newFixedThreadPool(CONCURRENT_CLIENT_REQUESTS);
|
||||
}
|
||||
|
||||
@After
|
||||
public void reset() throws InterruptedException {
|
||||
terminate(threadPoolExecutor);
|
||||
|
||||
clientBootstrap.shutdown();
|
||||
clientBootstrap.releaseExternalResources();
|
||||
|
||||
serverBootstrap.shutdown();
|
||||
serverBootstrap.releaseExternalResources();
|
||||
|
||||
failureCause.set(null);
|
||||
}
|
||||
|
||||
public void testWriteBeforeHandshakeFailsWithoutHandler() throws Exception {
|
||||
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
engine.setUseClientMode(true);
|
||||
return Channels.pipeline(
|
||||
new SslHandler(engine));
|
||||
}
|
||||
});
|
||||
|
||||
List<Callable<ChannelFuture>> callables = new ArrayList<>(CONCURRENT_CLIENT_REQUESTS);
|
||||
for (int i = 0; i < CONCURRENT_CLIENT_REQUESTS; i++) {
|
||||
callables.add(new WriteBeforeHandshakeCompletedCallable(clientBootstrap, randomPort));
|
||||
}
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
List<Future<ChannelFuture>> futures = threadPoolExecutor.invokeAll(callables);
|
||||
for (Future<ChannelFuture> future : futures) {
|
||||
ChannelFuture handshakeFuture = future.get();
|
||||
handshakeFuture.await();
|
||||
handshakeFuture.getChannel().close();
|
||||
}
|
||||
|
||||
if (failureCause.get() != null) {
|
||||
logger.info("run [{}] produced a failure", i);
|
||||
assertThat(failureCause.get(), anyOf(instanceOf(SSLException.class), instanceOf(AssertionError.class)));
|
||||
break;
|
||||
} else {
|
||||
logger.warn("run [{}] did not produce a failure", i);
|
||||
}
|
||||
}
|
||||
|
||||
assertThat("Expected this test to fail with an SSLException or AssertionError", failureCause.get(), notNullValue());
|
||||
}
|
||||
|
||||
public void testWriteBeforeHandshakePassesWithHandshakeWaitingHandler() throws Exception {
|
||||
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine engine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
engine.setUseClientMode(true);
|
||||
return Channels.pipeline(
|
||||
new SslHandler(engine),
|
||||
new Netty3HandshakeWaitingHandler(Loggers.getLogger(Netty3HandshakeWaitingHandler.class)));
|
||||
}
|
||||
});
|
||||
|
||||
List<Callable<ChannelFuture>> callables = new ArrayList<>(CONCURRENT_CLIENT_REQUESTS);
|
||||
for (int i = 0; i < CONCURRENT_CLIENT_REQUESTS; i++) {
|
||||
callables.add(new WriteBeforeHandshakeCompletedCallable(clientBootstrap, randomPort));
|
||||
}
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
List<Future<ChannelFuture>> futures = threadPoolExecutor.invokeAll(callables);
|
||||
for (Future<ChannelFuture> future : futures) {
|
||||
ChannelFuture handshakeFuture = future.get();
|
||||
handshakeFuture.await();
|
||||
|
||||
// Wait for pending writes to prevent IOExceptions
|
||||
Channel channel = handshakeFuture.getChannel();
|
||||
Netty3HandshakeWaitingHandler handler = channel.getPipeline().get(Netty3HandshakeWaitingHandler.class);
|
||||
if (handler != null) {
|
||||
boolean noMoreWrites = awaitBusy(() -> handler.hasPendingWrites() == false);
|
||||
assertTrue(noMoreWrites);
|
||||
}
|
||||
channel.close();
|
||||
}
|
||||
|
||||
assertNotFailed();
|
||||
logger.info("run [{}] succeeded", i);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertNotFailed() {
|
||||
if (failureCause.get() != null) {
|
||||
StringWriter writer = new StringWriter();
|
||||
if (failureCause.get() != null) {
|
||||
failureCause.get().printStackTrace(new PrintWriter(writer));
|
||||
}
|
||||
assertThat("Expected this test to always pass with the HandshakeWaitingHandler in pipeline\n" + writer.toString(),
|
||||
failureCause.get(), nullValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void startBootstrap() {
|
||||
serverBootstrap = new ServerBootstrap(new NioServerSocketChannelFactory());
|
||||
serverBootstrap.setPipelineFactory(getServerFactory());
|
||||
int tries = 1;
|
||||
int maxTries = 10;
|
||||
while (tries <= maxTries) {
|
||||
try {
|
||||
serverBootstrap.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), randomPort));
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (e.getCause() instanceof BindException) {
|
||||
logger.error("Tried to bind to port [{}], going to retry", randomPort);
|
||||
randomPort = randomIntBetween(49000, 65500);
|
||||
}
|
||||
if (tries >= maxTries) {
|
||||
throw new RuntimeException("Failed to start server bootstrap [" + tries + "] times, stopping", e);
|
||||
}
|
||||
tries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelPipelineFactory getServerFactory() {
|
||||
return new ChannelPipelineFactory() {
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
final SSLEngine sslEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
sslEngine.setUseClientMode(false);
|
||||
return Channels.pipeline(new SslHandler(sslEngine),
|
||||
new SimpleChannelHandler() {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
|
||||
// Sink the message
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
|
||||
Throwable cause = e.getCause();
|
||||
// Only save first cause
|
||||
failureCause.compareAndSet(null, cause);
|
||||
ctx.getChannel().close();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class WriteBeforeHandshakeCompletedCallable implements Callable<ChannelFuture> {
|
||||
|
||||
private final ClientBootstrap bootstrap;
|
||||
private final int port;
|
||||
|
||||
WriteBeforeHandshakeCompletedCallable(ClientBootstrap bootstrap, int port) {
|
||||
this.bootstrap = bootstrap;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture call() throws Exception {
|
||||
ChannelBuffer buffer = ChannelBuffers.buffer(8);
|
||||
buffer.writeLong(SecureRandom.getInstance("SHA1PRNG").nextLong());
|
||||
|
||||
// Connect and wait, then immediately start writing
|
||||
ChannelFuture future = bootstrap.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), port));
|
||||
future.awaitUninterruptibly();
|
||||
Channel channel = future.getChannel();
|
||||
|
||||
// Do not call handshake before writing as it will most likely succeed before a write begins
|
||||
// in the test
|
||||
ChannelFuture handshakeFuture = null;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (handshakeFuture == null) {
|
||||
handshakeFuture = channel.getPipeline().get(SslHandler.class).handshake();
|
||||
}
|
||||
channel.write(buffer);
|
||||
}
|
||||
|
||||
return handshakeFuture;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.http.HttpTransportSettings;
|
||||
import org.elasticsearch.http.netty3.Netty3HttpMockUtil;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class SecurityNetty3HttpServerTransportTests extends ESTestCase {
|
||||
|
||||
private SSLService sslService;
|
||||
private Environment env;
|
||||
|
||||
@Before
|
||||
public void createSSLService() throws Exception {
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.REQUIRED).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.client_authentication", SSLClientAuth.NONE).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testCustomSSLConfiguration() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
SSLEngine defaultEngine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
|
||||
settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put("xpack.security.http.ssl.supported_protocols", "TLSv1.2")
|
||||
.build();
|
||||
sslService = new SSLService(settings, new Environment(settings));
|
||||
transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
Netty3HttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
factory = transport.configureServerChannelPipelineFactory();
|
||||
SSLEngine customEngine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
assertThat(customEngine.getEnabledProtocols(), arrayContaining("TLSv1.2"));
|
||||
assertThat(customEngine.getEnabledProtocols(), not(equalTo(defaultEngine.getEnabledProtocols())));
|
||||
}
|
||||
|
||||
public void testDisablesCompressionByDefaultForSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.http.ssl.enabled", true).build();
|
||||
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
assertThat(HttpTransportSettings.SETTING_HTTP_COMPRESSION.get(pluginSettingsBuilder.build()), is(false));
|
||||
}
|
||||
|
||||
public void testLeavesCompressionOnIfNotSsl() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.http.ssl.enabled", false).build();
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
assertThat(pluginSettingsBuilder.build().isEmpty(), is(true));
|
||||
}
|
||||
|
||||
public void testDoesNotChangeExplicitlySetCompression() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.http.ssl.enabled", true)
|
||||
.put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true)
|
||||
.build();
|
||||
|
||||
Settings.Builder pluginSettingsBuilder = Settings.builder();
|
||||
SecurityNetty3HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
|
||||
assertThat(pluginSettingsBuilder.build().isEmpty(), 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("xpack.security.http.ssl.enabled", true)
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, transport::configureServerChannelPipelineFactory);
|
||||
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("path.home", createTempDir())
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3HttpServerTransport transport = new SecurityNetty3HttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), sslService, mock(ThreadPool.class));
|
||||
assertNotNull(transport.configureServerChannelPipelineFactory());
|
||||
}
|
||||
}
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.netty3.Netty3MockUtil;
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory;
|
||||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
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 SecurityNetty3TransportTests extends ESTestCase {
|
||||
|
||||
private Environment env;
|
||||
private SSLService sslService;
|
||||
|
||||
@Before
|
||||
public void createSSLService() throws Exception {
|
||||
Path testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings settings = Settings.builder()
|
||||
.put("path.home", createTempDir())
|
||||
.put("xpack.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeDisabledByProfile() throws Exception {
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl.enabled", false).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class), nullValue());
|
||||
}
|
||||
|
||||
public void testThatSSLCanBeEnabledByProfile() throws Exception {
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", false).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl.enabled", true).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());
|
||||
}
|
||||
|
||||
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine(), notNullValue());
|
||||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true).build();
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testRequiredClientAuth() throws Exception {
|
||||
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("xpack.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testNoClientAuth() throws Exception {
|
||||
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("xpack.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testOptionalClientAuth() throws Exception {
|
||||
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("xpack.ssl.client_authentication", value).build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testProfileRequiredClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileNoClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.NONE.name(), SSLClientAuth.NONE.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), null, sslService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testProfileOptionalClientAuth() throws Exception {
|
||||
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
|
||||
Settings settings = Settings.builder()
|
||||
.put(env.settings())
|
||||
.put("xpack.security.transport.ssl.enabled", true)
|
||||
.put("transport.profiles.client.xpack.security.ssl.client_authentication", value)
|
||||
.build();
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl.client_authentication", value).build());
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(true));
|
||||
}
|
||||
|
||||
public void testThatExceptionIsThrownWhenConfiguredWithoutSslKey() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.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);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> transport.configureServerChannelPipelineFactory(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);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
assertNotNull(transport.configureServerChannelPipelineFactory(randomAsciiOfLength(6), Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testTransportSSLOverridesGlobalSSL() throws Exception {
|
||||
final boolean useGlobalKeystoreWithoutKey = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put("xpack.security.transport.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||
.put("xpack.security.transport.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.transport.ssl.client_authentication", "none")
|
||||
.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true)
|
||||
.put("path.home", createTempDir());
|
||||
if (useGlobalKeystoreWithoutKey) {
|
||||
builder.put("xpack.ssl.keystore.path",
|
||||
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks"))
|
||||
.put("xpack.ssl.keystore.password", "truststore-testnode-only");
|
||||
}
|
||||
Settings settings = builder.build();
|
||||
env = new Environment(settings);
|
||||
sslService = new SSLService(settings, env);
|
||||
SecurityNetty3Transport transport = new SecurityNetty3Transport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), null, sslService,
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class));
|
||||
Netty3MockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("default", Settings.EMPTY);
|
||||
final SSLEngine engine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
assertFalse(engine.getNeedClientAuth());
|
||||
assertFalse(engine.getWantClientAuth());
|
||||
|
||||
// get the global and verify that it is different in that it requires client auth
|
||||
final SSLEngine globalEngine = sslService.createSSLEngine(Settings.EMPTY, Settings.EMPTY);
|
||||
assertTrue(globalEngine.getNeedClientAuth());
|
||||
assertFalse(globalEngine.getWantClientAuth());
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
package org.elasticsearch.xpack.security.transport.netty4;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.settings.Settings;
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.transport.netty3;
|
||||
package org.elasticsearch.xpack.security.transport.netty4;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.transport.NoNodeAvailableException;
|
|
@ -15,7 +15,6 @@ import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
|||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
|
@ -48,7 +47,7 @@ public class WatcherPluginDisableTests extends ESIntegTestCase {
|
|||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
return Arrays.asList(XPackPlugin.class, Netty3Plugin.class, Netty4Plugin.class);
|
||||
return Arrays.asList(XPackPlugin.class, Netty4Plugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.watcher.actions.email;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
|
@ -45,7 +46,6 @@ import org.elasticsearch.xpack.watcher.support.xcontent.WatcherParams;
|
|||
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
|
||||
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Before;
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.elasticsearch.common.network.NetworkModule;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth;
|
||||
|
@ -48,7 +47,6 @@ public class ChainIntegrationTests extends AbstractWatcherIntegrationTestCase {
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.watcher.client.WatcherClient;
|
||||
import org.elasticsearch.xpack.watcher.condition.CompareCondition;
|
||||
|
@ -54,7 +53,6 @@ public class HttpInputIntegrationTests extends AbstractWatcherIntegrationTestCas
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.watcher.input.http;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
@ -39,7 +40,6 @@ import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
|||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
import org.elasticsearch.xpack.watcher.watch.Watch;
|
||||
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.watcher.test;
|
||||
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
||||
|
@ -73,7 +74,6 @@ import org.elasticsearch.xpack.watcher.trigger.TriggerService;
|
|||
import org.elasticsearch.xpack.watcher.watch.Watch;
|
||||
import org.elasticsearch.xpack.watcher.watch.WatchStore;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.jboss.netty.util.internal.SystemPropertyUtil;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
@ -123,13 +123,6 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
|||
|
||||
private static String scheduleEngineName;
|
||||
|
||||
private boolean useSecurity3;
|
||||
|
||||
@Before
|
||||
public void setUseSecurity3() {
|
||||
useSecurity3 = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestCluster buildTestCluster(Scope scope, long seed) throws IOException {
|
||||
if (securityEnabled == null) {
|
||||
|
@ -150,7 +143,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
|||
.put("index.store.mock.check_index_on_close", false)
|
||||
.put("xpack.watcher.execution.scroll.size", randomIntBetween(1, 100))
|
||||
.put("xpack.watcher.watch.scroll.size", randomIntBetween(1, 100))
|
||||
.put(SecuritySettings.settings(securityEnabled, useSecurity3))
|
||||
.put(SecuritySettings.settings(securityEnabled))
|
||||
.put("xpack.watcher.trigger.schedule.engine", scheduleEngineName)
|
||||
.put("script.inline", "true")
|
||||
.build();
|
||||
|
@ -274,8 +267,8 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
|||
return Settings.builder()
|
||||
.put("client.transport.sniff", false)
|
||||
.put(Security.USER_SETTING.getKey(), "admin:changeme")
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, useSecurity3 ? Security.NAME3 : Security.NAME4)
|
||||
.put(NetworkModule.HTTP_TYPE_KEY, useSecurity3 ? Security.NAME3 : Security.NAME4)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4)
|
||||
.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -743,7 +736,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
|||
;
|
||||
|
||||
|
||||
public static Settings settings(boolean enabled, boolean useSecurity3) {
|
||||
public static Settings settings(boolean enabled) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
if (!enabled) {
|
||||
return builder.put("xpack.security.enabled", false).build();
|
||||
|
@ -763,15 +756,10 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
|
|||
.put("xpack.security.authc.sign_user_header", false)
|
||||
.put("xpack.security.audit.enabled", auditLogsEnabled)
|
||||
.put(Environment.PATH_CONF_SETTING.getKey(), conf);
|
||||
if (useSecurity3) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3);
|
||||
builder.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME3);
|
||||
} else {
|
||||
// security should always use one of its transports so if it is enabled explicitly declare one otherwise a local
|
||||
// transport could be used
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
builder.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4);
|
||||
}
|
||||
// security should always use one of its transports so if it is enabled explicitly declare one otherwise a local
|
||||
// transport could be used
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
builder.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4);
|
||||
return builder.build();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("failed to build settings for security", ex);
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.transport.Netty3Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
|
@ -55,7 +54,6 @@ public class WatcherSettingsFilterTests extends AbstractWatcherIntegrationTestCa
|
|||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
|
||||
plugins.add(Netty3Plugin.class); // for http
|
||||
plugins.add(Netty4Plugin.class); // for http
|
||||
return plugins;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ public class IndexAuditIT extends ESIntegTestCase {
|
|||
protected Settings externalClusterClientSettings() {
|
||||
return Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,14 +23,6 @@ import java.util.Collections;
|
|||
|
||||
public class ReindexWithSecurityIT extends SecurityIntegTestCase {
|
||||
|
||||
private boolean useSecurity3;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
useSecurity3 = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
|
@ -49,11 +41,7 @@ public class ReindexWithSecurityIT extends SecurityIntegTestCase {
|
|||
@Override
|
||||
protected Settings externalClusterClientSettings() {
|
||||
Settings.Builder builder = Settings.builder().put(super.externalClusterClientSettings());
|
||||
if (useSecurity3) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3);
|
||||
} else {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
}
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
builder.put(Security.USER_SETTING.getKey(), "test_admin:changeme");
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
|
|||
protected Settings externalClusterClientSettings() {
|
||||
return Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), ADMIN_USER_PW)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public class CustomRealmIT extends ESIntegTestCase {
|
|||
return Settings.builder()
|
||||
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
|
||||
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,16 +45,6 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|||
* indexed in the cluster.
|
||||
*/
|
||||
public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
||||
|
||||
private boolean useSecurity3;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
useSecurity3 = randomBoolean();
|
||||
}
|
||||
|
||||
private static final String USER = "test_user";
|
||||
private static final String PASS = "changeme";
|
||||
private static final String KEYSTORE_PASS = "keypass";
|
||||
|
@ -67,18 +57,12 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
|
|||
|
||||
@Override
|
||||
protected Settings externalClusterClientSettings() {
|
||||
final Settings.Builder builder =
|
||||
Settings.builder()
|
||||
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);
|
||||
if (useSecurity3) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3);
|
||||
} else {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
}
|
||||
return builder.build();
|
||||
.put("xpack.ssl.keystore.password", KEYSTORE_PASS)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4).build();
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
Loading…
Reference in New Issue