Migrate Netty 4 unit tests

This commit migrates some unit tests to Netty 4.

Original commit: elastic/x-pack-elasticsearch@a38dc82706
This commit is contained in:
Jason Tedor 2016-08-02 16:42:24 -04:00
parent c3cecad027
commit c88aea19d8
8 changed files with 873 additions and 23 deletions

View File

@ -47,31 +47,50 @@ public class SecurityNetty3Transport extends Netty3Transport {
public static final boolean SSL_DEFAULT = false;
public static final Setting<Boolean> DEPRECATED_HOSTNAME_VERIFICATION_SETTING =
Setting.boolSetting(setting("ssl.hostname_verification"), true, Property.NodeScope, Property.Filtered, Property.Deprecated);
Setting.boolSetting(
setting("ssl.hostname_verification"),
true,
new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared});
public static final Setting<Boolean> HOSTNAME_VERIFICATION_SETTING =
Setting.boolSetting(featureEnabledSetting("ssl.hostname_verification"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING,
Property.NodeScope, Property.Filtered);
Property.NodeScope, Property.Filtered, Property.Shared);
public static final Setting<Boolean> HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING =
Setting.boolSetting(setting("ssl.hostname_verification.resolve_name"), true, Property.NodeScope, Property.Filtered);
Setting.boolSetting(
setting("ssl.hostname_verification.resolve_name"),
true,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT,
Property.Filtered, Property.NodeScope, Property.Deprecated);
Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
public static final Setting<Boolean> SSL_SETTING =
Setting.boolSetting(setting("transport.ssl.enabled"), DEPRECATED_SSL_SETTING, Property.Filtered, Property.NodeScope);
Setting.boolSetting(
setting("transport.ssl.enabled"),
DEPRECATED_SSL_SETTING,
new Property[]{Property.Filtered, Property.NodeScope, Property.Shared});
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
new Setting<>(setting("transport.ssl.client.auth"), CLIENT_AUTH_DEFAULT,
SSLClientAuth::parse, Property.NodeScope, Property.Filtered);
new Setting<>(
setting("transport.ssl.client.auth"),
CLIENT_AUTH_DEFAULT,
SSLClientAuth::parse,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
public static final Setting<Boolean> DEPRECATED_PROFILE_SSL_SETTING =
Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated);
Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
public static final Setting<Boolean> PROFILE_SSL_SETTING =
Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope);
Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared);
public static final Setting<SSLClientAuth> PROFILE_CLIENT_AUTH_SETTING =
new Setting<>(setting("ssl.client.auth"), CLIENT_AUTH_SETTING, SSLClientAuth::parse,
Property.NodeScope, Property.Filtered);
new Setting<>(
setting("ssl.client.auth"),
CLIENT_AUTH_SETTING,
SSLClientAuth::parse,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
private final ServerSSLService serverSslService;
private final ClientSSLService clientSSLService;

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.security.transport.netty4;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
@ -107,7 +108,7 @@ public class SecurityNetty4HttpServerTransport extends Netty4HttpServerTransport
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
if (ssl) {
final SSLEngine engine = sslService.createSSLEngine(sslSettings);

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.security.transport.netty4;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
@ -18,6 +19,7 @@ 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;
@ -35,20 +37,67 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.xpack.security.Security.featureEnabledSetting;
import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.Security.settingPrefix;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.CLIENT_AUTH_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.DEPRECATED_PROFILE_SSL_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.HOSTNAME_VERIFICATION_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.PROFILE_CLIENT_AUTH_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.PROFILE_SSL_SETTING;
import static org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport.SSL_SETTING;
import org.elasticsearch.common.settings.Setting.Property;
/**
* Implementation of a transport that extends the {@link Netty4Transport} to add SSL and IP Filtering
*/
public class SecurityNetty4Transport extends Netty4Transport {
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name();
public static final boolean SSL_DEFAULT = false;
public static final Setting<Boolean> DEPRECATED_HOSTNAME_VERIFICATION_SETTING =
Setting.boolSetting(
setting("ssl.hostname_verification"),
true,
new Property[]{Property.NodeScope, Property.Filtered, Property.Deprecated, Property.Shared});
public static final Setting<Boolean> HOSTNAME_VERIFICATION_SETTING =
Setting.boolSetting(featureEnabledSetting("ssl.hostname_verification"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING,
Property.NodeScope, Property.Filtered, Property.Shared);
public static final Setting<Boolean> HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING =
Setting.boolSetting(
setting("ssl.hostname_verification.resolve_name"),
true,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
public static final Setting<Boolean> DEPRECATED_SSL_SETTING =
Setting.boolSetting(setting("transport.ssl"), SSL_DEFAULT,
Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
public static final Setting<Boolean> SSL_SETTING =
Setting.boolSetting(
setting("transport.ssl.enabled"),
DEPRECATED_SSL_SETTING,
new Property[]{Property.Filtered, Property.NodeScope, Property.Shared});
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
new Setting<>(
setting("transport.ssl.client.auth"),
CLIENT_AUTH_DEFAULT,
SSLClientAuth::parse,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
public static final Setting<Boolean> DEPRECATED_PROFILE_SSL_SETTING =
Setting.boolSetting(setting("ssl"), SSL_SETTING, Property.Filtered, Property.NodeScope, Property.Deprecated, Property.Shared);
public static final Setting<Boolean> PROFILE_SSL_SETTING =
Setting.boolSetting(setting("ssl.enabled"), SSL_DEFAULT, Property.Filtered, Property.NodeScope, Property.Shared);
public static final Setting<SSLClientAuth> PROFILE_CLIENT_AUTH_SETTING =
new Setting<>(
setting("ssl.client.auth"),
CLIENT_AUTH_SETTING,
SSLClientAuth::parse,
new Property[]{Property.NodeScope, Property.Filtered, Property.Shared});
private final ServerSSLService serverSslService;
private final ClientSSLService clientSSLService;
@Nullable private final IPFilter authenticator;
@ -77,12 +126,12 @@ public class SecurityNetty4Transport extends Netty4Transport {
}
@Override
protected ChannelInitializer<SocketChannel> getServerChannelInitializer(String name, Settings settings) {
protected ChannelHandler getServerChannelInitializer(String name, Settings settings) {
return new SecurityServerChannelInitializer(name, settings);
}
@Override
protected ChannelInitializer<SocketChannel> getClientChannelInitializer() {
protected ChannelHandler getClientChannelInitializer() {
return new SecurityClientChannelInitializer();
}
@ -113,7 +162,7 @@ public class SecurityNetty4Transport extends Netty4Transport {
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
if (sslEnabled) {
Settings securityProfileSettings = settings.getByPrefix(settingPrefix());
@ -131,7 +180,7 @@ public class SecurityNetty4Transport extends Netty4Transport {
class SecurityClientChannelInitializer extends ClientChannelInitializer {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
if (ssl) {
ch.pipeline().addFirst(new ClientSslHandlerInitializer());

View File

@ -0,0 +1,23 @@
/*
* 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.netty4;
import org.elasticsearch.transport.netty4.Netty4OpenChannelsHandler;
import static org.mockito.Mockito.mock;
/** Allows setting a mock into Netty3HttpServerTransport */
public class Netty4HttpMockUtil {
/**
* 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(Netty4HttpServerTransport transport) throws Exception {
transport.serverOpenChannels = mock(Netty4OpenChannelsHandler.class);
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.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 */
public class Netty4MockUtil {
/**
* 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(Netty4Transport transport) throws Exception {
transport.serverOpenChannels = mock(Netty4OpenChannelsHandler.class);
}
}

View File

@ -0,0 +1,314 @@
/*
* 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.netty4;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.EventExecutor;
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.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.elasticsearch.xpack.security.transport.netty3.IPFilterNetty3UpstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
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 IpFilterRemoteAddressFilterTests extends ESTestCase {
private IpFilterRemoteAddressFilter handler;
@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);
InetSocketTransportAddress address = new InetSocketTransportAddress(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);
InetSocketTransportAddress httpAddress = new InetSocketTransportAddress(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) {
handler = new IpFilterRemoteAddressFilter(ipFilter, IPFilter.HTTP_PROFILE_NAME);
} else {
handler = new IpFilterRemoteAddressFilter(ipFilter, "default");
}
}
public void testThatFilteringWorksByIp() throws Exception {
InetSocketAddress localhostAddr = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 12345);
assertThat(handler.accept(new NullChannelHandlerContext(), localhostAddr), is(true));
InetSocketAddress remoteAddr = new InetSocketAddress(InetAddresses.forString("10.0.0.8"), 12345);
assertThat(handler.accept(new NullChannelHandlerContext(), remoteAddr), is(false));
}
private static class NullChannelHandlerContext implements ChannelHandlerContext {
@Override
public Channel channel() {
return null;
}
@Override
public EventExecutor executor() {
return null;
}
@Override
public String name() {
return null;
}
@Override
public ChannelHandler handler() {
return null;
}
@Override
public boolean isRemoved() {
return false;
}
@Override
public ChannelHandlerContext fireChannelRegistered() {
return null;
}
@Override
public ChannelHandlerContext fireChannelUnregistered() {
return null;
}
@Override
public ChannelHandlerContext fireChannelActive() {
return null;
}
@Override
public ChannelHandlerContext fireChannelInactive() {
return null;
}
@Override
public ChannelHandlerContext fireExceptionCaught(Throwable cause) {
return null;
}
@Override
public ChannelHandlerContext fireUserEventTriggered(Object evt) {
return null;
}
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
return null;
}
@Override
public ChannelHandlerContext fireChannelReadComplete() {
return null;
}
@Override
public ChannelHandlerContext fireChannelWritabilityChanged() {
return null;
}
@Override
public ChannelHandlerContext read() {
return null;
}
@Override
public ChannelHandlerContext flush() {
return null;
}
@Override
public ChannelPipeline pipeline() {
return null;
}
@Override
public ByteBufAllocator alloc() {
return null;
}
@Override
public <T> Attribute<T> attr(AttributeKey<T> key) {
return null;
}
@Override
public <T> boolean hasAttr(AttributeKey<T> key) {
return false;
}
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return null;
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress) {
return null;
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return null;
}
@Override
public ChannelFuture disconnect() {
return null;
}
@Override
public ChannelFuture close() {
return null;
}
@Override
public ChannelFuture deregister() {
return null;
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture disconnect(ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture close(ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture deregister(ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture write(Object msg) {
return null;
}
@Override
public ChannelFuture write(Object msg, ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return null;
}
@Override
public ChannelFuture writeAndFlush(Object msg) {
return null;
}
@Override
public ChannelPromise newPromise() {
return null;
}
@Override
public ChannelProgressivePromise newProgressivePromise() {
return null;
}
@Override
public ChannelFuture newSucceededFuture() {
return null;
}
@Override
public ChannelFuture newFailedFuture(Throwable cause) {
return null;
}
@Override
public ChannelPromise voidPromise() {
return null;
}
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.netty4;
import io.netty.channel.ChannelHandler;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.ssl.SslHandler;
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.netty4.Netty4HttpMockUtil;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
import org.elasticsearch.xpack.security.ssl.ServerSSLService;
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
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.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.mockito.Mockito.mock;
public class SecurityNetty4HttpServerTransportTests extends ESTestCase {
private ServerSSLService serverSSLService;
@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.security.ssl.keystore.path", testNodeStore)
.put("xpack.security.ssl.keystore.password", "testnode")
.build();
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
serverSSLService = new ServerSSLService(settings, env, new Global(settings));
}
public void testDefaultClientAuth() throws Exception {
Settings settings = Settings.builder().put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.configureServerChannelHandler();
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testOptionalClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.configureServerChannelHandler();
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
}
public void testRequiredClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.configureServerChannelHandler();
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testNoClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.NO.name(), SSLClientAuth.NO.name().toLowerCase(Locale.ROOT), "false", "FALSE");
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4HttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.configureServerChannelHandler();
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testCustomSSLConfiguration() throws Exception {
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
SecurityNetty4HttpServerTransport transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.configureServerChannelHandler();
EmbeddedChannel ch = new EmbeddedChannel(handler);
SSLEngine defaultEngine = ch.pipeline().get(SslHandler.class).engine();
settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
.put("xpack.security.http.ssl.supported_protocols", "TLSv1.2")
.build();
transport = new SecurityNetty4HttpServerTransport(settings, mock(NetworkService.class),
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
Netty4HttpMockUtil.setOpenChannelsHandlerToMock(transport);
handler = transport.configureServerChannelHandler();
ch = new EmbeddedChannel(handler);
SSLEngine customEngine = ch.pipeline().get(SslHandler.class).engine();
assertThat(customEngine.getEnabledProtocols(), arrayContaining("TLSv1.2"));
assertThat(customEngine.getEnabledProtocols(), not(equalTo(defaultEngine.getEnabledProtocols())));
}
public void testDisablesCompressionByDefaultForSsl() throws Exception {
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true).build();
Settings.Builder pluginSettingsBuilder = Settings.builder();
SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
assertThat(HttpTransportSettings.SETTING_HTTP_COMPRESSION.get(pluginSettingsBuilder.build()), is(false));
}
public void testLeavesCompressionOnIfNotSsl() throws Exception {
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), false).build();
Settings.Builder pluginSettingsBuilder = Settings.builder();
SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
assertThat(pluginSettingsBuilder.build().isEmpty(), is(true));
}
public void testDoesNotChangeExplicitlySetCompression() throws Exception {
Settings settings = Settings.builder()
.put(SecurityNetty4HttpServerTransport.SSL_SETTING.getKey(), true)
.put(HttpTransportSettings.SETTING_HTTP_COMPRESSION.getKey(), true)
.build();
Settings.Builder pluginSettingsBuilder = Settings.builder();
SecurityNetty4HttpServerTransport.overrideSettings(pluginSettingsBuilder, settings);
assertThat(pluginSettingsBuilder.build().isEmpty(), is(true));
}
}

View File

@ -0,0 +1,265 @@
/*
* 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.netty4;
import io.netty.channel.ChannelHandler;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.ssl.SslHandler;
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.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.netty4.Netty4MockUtil;
import org.elasticsearch.xpack.security.ssl.ClientSSLService;
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
import org.elasticsearch.xpack.security.ssl.ServerSSLService;
import org.elasticsearch.xpack.security.transport.SSLClientAuth;
import org.junit.Before;
import java.nio.file.Path;
import java.util.Locale;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
public class SecurityNetty4TransportTests extends ESTestCase {
private ServerSSLService serverSSLService;
private ClientSSLService clientSSLService;
@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.security.ssl.keystore.path", testnodeStore)
.put("xpack.security.ssl.keystore.password", "testnode")
.build();
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
Global globalSSLConfiguration = new Global(settings);
serverSSLService = new ServerSSLService(settings, env, globalSSLConfiguration);
clientSSLService = new ClientSSLService(settings, env, globalSSLConfiguration);
}
public void testThatSSLCanBeDisabledByProfile() throws Exception {
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client",
Settings.builder().put("xpack.security.ssl", false).build());
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class), nullValue());
}
public void testThatSSLCanBeEnabledByProfile() throws Exception {
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), false).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client",
Settings.builder().put("xpack.security.ssl", true).build());
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class), notNullValue());
}
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine(), notNullValue());
}
public void testDefaultClientAuth() throws Exception {
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testRequiredClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true");
Settings settings = Settings.builder()
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testNoClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
Settings settings = Settings.builder()
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testOptionalClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
Settings settings = Settings.builder()
.put(SecurityNetty4Transport.SSL_SETTING.getKey(), true)
.put(SecurityNetty4Transport.CLIENT_AUTH_SETTING.getKey(), value).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client", Settings.EMPTY);
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
}
public void testProfileRequiredClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.REQUIRED.name(), SSLClientAuth.REQUIRED.name().toLowerCase(Locale.ROOT), "true", "TRUE");
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client",
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING, value).build());
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(true));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testProfileNoClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.NO.name(), "false", "FALSE", SSLClientAuth.NO.name().toLowerCase(Locale.ROOT));
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
ChannelHandler handler = transport.getServerChannelInitializer("client",
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(false));
}
public void testProfileOptionalClientAuth() throws Exception {
String value = randomFrom(SSLClientAuth.OPTIONAL.name(), SSLClientAuth.OPTIONAL.name().toLowerCase(Locale.ROOT));
Settings settings = Settings.builder().put(SecurityNetty4Transport.SSL_SETTING.getKey(), true).build();
SecurityNetty4Transport transport =
new SecurityNetty4Transport(
settings,
mock(ThreadPool.class),
mock(NetworkService.class),
mock(BigArrays.class),
mock(NamedWriteableRegistry.class),
mock(CircuitBreakerService.class),
null,
serverSSLService,
clientSSLService);
Netty4MockUtil.setOpenChannelsHandlerToMock(transport);
final ChannelHandler handler = transport.getServerChannelInitializer("client",
Settings.builder().put(SecurityNetty4Transport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
final EmbeddedChannel ch = new EmbeddedChannel(handler);
assertThat(ch.pipeline().get(SslHandler.class).engine().getNeedClientAuth(), is(false));
assertThat(ch.pipeline().get(SslHandler.class).engine().getWantClientAuth(), is(true));
}
}