Testing: Create ShieldIntegrationTest that other test inherit from

This integration test contains all of the configuration needed to run with shield
and will be the base for further improvements.

Closes elastic/elasticsearch#36
Relates elastic/elasticsearch#31

Original commit: elastic/x-pack-elasticsearch@fe77f4d32b
This commit is contained in:
Alexander Reelsen 2014-08-28 09:28:51 +02:00
parent fcd3a89a3d
commit d0e377ff76
9 changed files with 325 additions and 343 deletions

View File

@ -26,29 +26,35 @@ import org.elasticsearch.shield.transport.netty.NettySecuredTransportModule;
public class SecurityModule extends AbstractModule implements SpawnModules, PreProcessModule { public class SecurityModule extends AbstractModule implements SpawnModules, PreProcessModule {
private final Settings settings; private final Settings settings;
private final boolean isClient;
private final boolean isShieldEnabled;
public SecurityModule(Settings settings) { public SecurityModule(Settings settings) {
this.settings = settings; this.settings = settings;
this.isClient = settings.getAsBoolean("node.client", false);
this.isShieldEnabled = settings.getComponentSettings(SecurityModule.class).getAsBoolean("enabled", true);
} }
@Override @Override
public void processModule(Module module) { public void processModule(Module module) {
if (module instanceof ActionModule) { if (module instanceof ActionModule && isShieldEnabled && !isClient) {
((ActionModule) module).registerFilter(SecurityFilter.Action.class); ((ActionModule) module).registerFilter(SecurityFilter.Action.class);
} }
} }
@Override @Override
public Iterable<? extends Module> spawnModules() { public Iterable<? extends Module> spawnModules() {
// don't spawn modules if shield is explicitly disabled
// don't spawn module in client mode if (!isShieldEnabled) {
if (settings.getAsBoolean("node.client", false)) {
return ImmutableList.of(); return ImmutableList.of();
} }
// don't spawn modules if shield is explicitly disabled // spawn needed parts in client mode
if (!settings.getComponentSettings(SecurityModule.class).getAsBoolean("enabled", true)) { if (isClient) {
return ImmutableList.of(); return ImmutableList.of(
new N2NModule(),
new SecuredTransportModule()
);
} }
return ImmutableList.of( return ImmutableList.of(
@ -58,7 +64,7 @@ public class SecurityModule extends AbstractModule implements SpawnModules, PreP
new N2NModule(), new N2NModule(),
new NettySecuredHttpServerTransportModule(), new NettySecuredHttpServerTransportModule(),
new NettySecuredTransportModule(), new NettySecuredTransportModule(),
new SecuredTransportModule(settings)); new SecuredTransportModule());
} }
@Override @Override

View File

@ -6,7 +6,6 @@
package org.elasticsearch.shield.transport; package org.elasticsearch.shield.transport;
import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.SecurityFilter; import org.elasticsearch.shield.SecurityFilter;
/** /**
@ -14,16 +13,8 @@ import org.elasticsearch.shield.SecurityFilter;
*/ */
public class SecuredTransportModule extends AbstractModule { public class SecuredTransportModule extends AbstractModule {
private final Settings settings;
public SecuredTransportModule(Settings settings) {
this.settings = settings;
}
@Override @Override
protected void configure() { protected void configure() {
if (!settings.getAsBoolean("node.client", false)) {
bind(TransportFilter.class).to(SecurityFilter.Transport.class).asEagerSingleton(); bind(TransportFilter.class).to(SecurityFilter.Transport.class).asEagerSingleton();
} }
} }
}

View File

@ -30,10 +30,10 @@ public class SecuredMessageChannelHandler extends MessageChannelHandler {
@Override @Override
public void operationComplete(ChannelFuture future) throws Exception { public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) { if (future.isSuccess()) {
logger.debug("SSL / TLS handshake completed for the channel."); logger.debug("SSL / TLS handshake completed for channel", ctx.getName());
ctx.sendUpstream(e); ctx.sendUpstream(e);
} else { } else {
logger.error("SSL / TLS handshake failed, closing the channel"); logger.error("SSL / TLS handshake failed, closing channel", ctx.getName());
future.getChannel().close(); future.getChannel().close();
throw new ElasticsearchSSLException("SSL / TLS handshake failed, closing the channel", future.getCause()); throw new ElasticsearchSSLException("SSL / TLS handshake failed, closing the channel", future.getCause());
} }

View File

@ -52,9 +52,6 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
@Before @Before
public void init() throws Exception { public void init() throws Exception {
configFile = temporaryFolder.newFile(); configFile = temporaryFolder.newFile();
Settings resourceWatcherServiceSettings = settingsBuilder().put("watcher.interval.medium", TimeValue.timeValueMillis(200)).build();
resourceWatcherService = new ResourceWatcherService(resourceWatcherServiceSettings, new ThreadPool("resourceWatcher")).start();
settings = settingsBuilder().put("shield.n2n.file", configFile.getPath()).build();
} }
@After @After
@ -66,75 +63,75 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
public void testThatIpV4AddressesCanBeProcessed() throws Exception { public void testThatIpV4AddressesCanBeProcessed() throws Exception {
writeConfigFile("allow: 127.0.0.1\ndeny: 10.0.0.0/8"); writeConfigFile("allow: 127.0.0.1\ndeny: 10.0.0.0/8");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "10.2.3.4"); assertAddressIsDenied("10.2.3.4");
} }
@Test @Test
public void testThatIpV6AddressesCanBeProcessed() throws Exception { public void testThatIpV6AddressesCanBeProcessed() throws Exception {
writeConfigFile("allow: 2001:0db8:1234::/48\ndeny: 1234:0db8:85a3:0000:0000:8a2e:0370:7334"); writeConfigFile("allow: 2001:0db8:1234::/48\ndeny: 1234:0db8:85a3:0000:0000:8a2e:0370:7334");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "2001:0db8:1234:0000:0000:8a2e:0370:7334"); assertAddressIsAllowed("2001:0db8:1234:0000:0000:8a2e:0370:7334");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "1234:0db8:85a3:0000:0000:8a2e:0370:7334"); assertAddressIsDenied("1234:0db8:85a3:0000:0000:8a2e:0370:7334");
} }
@Test @Test
public void testThatHostnamesCanBeProcessed() throws Exception { public void testThatHostnamesCanBeProcessed() throws Exception {
writeConfigFile("allow: localhost\ndeny: '*.google.com'"); writeConfigFile("allow: localhost\ndeny: '*.google.com'");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "173.194.70.100"); assertAddressIsDenied("173.194.70.100");
} }
@Test @Test
public void testThatFileDeletionResultsInAllowingAll() throws Exception { public void testThatFileDeletionResultsInAllowingAll() throws Exception {
writeConfigFile("allow: 127.0.0.1"); writeConfigFile("allow: 127.0.0.1");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
configFile.delete(); configFile.delete();
assertThat(configFile.exists(), is(false)); assertThat(configFile.exists(), is(false));
sleep(250); sleep(250);
assertAddressIsDenied(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsDenied("127.0.0.1");
} }
@Test @Test
public void testThatAnAllowAllAuthenticatorWorks() throws Exception { public void testThatAnAllowAllAuthenticatorWorks() throws Exception {
writeConfigFile("allow: all"); writeConfigFile("allow: all");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "173.194.70.100"); assertAddressIsAllowed("173.194.70.100");
} }
@Test @Test
public void testThatCommaSeparatedValuesWork() throws Exception { public void testThatCommaSeparatedValuesWork() throws Exception {
writeConfigFile("allow: 192.168.23.0/24, localhost\ndeny: all"); writeConfigFile("allow: 192.168.23.0/24, localhost\ndeny: all");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "192.168.23.1"); assertAddressIsAllowed("192.168.23.1");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "10.1.2.3"); assertAddressIsDenied("10.1.2.3");
} }
@Test @Test
public void testThatOrderIsImportant() throws Exception { public void testThatOrderIsImportant() throws Exception {
writeConfigFile("deny: localhost\nallow: localhost"); writeConfigFile("deny: localhost\nallow: localhost");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsDenied("127.0.0.1");
} }
@Test @Test
public void testThatOrderIsImportantViceVersa() throws Exception { public void testThatOrderIsImportantViceVersa() throws Exception {
writeConfigFile("allow: localhost\ndeny: localhost"); writeConfigFile("allow: localhost\ndeny: localhost");
assertAddressIsAllowed(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsAllowed("127.0.0.1");
} }
@Test @Test
public void testThatEmptyFileDoesNotLeadIntoLoop() throws Exception { public void testThatEmptyFileDoesNotLeadIntoLoop() throws Exception {
writeConfigFile("# \n\n"); writeConfigFile("# \n\n");
assertAddressIsDenied(ipFilteringN2NAuthenticator, "127.0.0.1"); assertAddressIsDenied("127.0.0.1");
} }
@Test(expected = ElasticsearchParseException.class) @Test(expected = ElasticsearchParseException.class)
@ -145,17 +142,20 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
private void writeConfigFile(String data) throws IOException { private void writeConfigFile(String data) throws IOException {
Files.write(data.getBytes(Charsets.UTF_8), configFile); Files.write(data.getBytes(Charsets.UTF_8), configFile);
Settings resourceWatcherServiceSettings = settingsBuilder().put("watcher.interval.medium", TimeValue.timeValueMillis(200)).build();
resourceWatcherService = new ResourceWatcherService(resourceWatcherServiceSettings, new ThreadPool("resourceWatcher")).start();
settings = settingsBuilder().put("shield.n2n.file", configFile.getPath()).build();
ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService); ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService);
} }
private void assertAddressIsAllowed(IPFilteringN2NAuthenticator ipFilteringN2NAuthenticator, String ... inetAddresses) { private void assertAddressIsAllowed(String ... inetAddresses) {
for (String inetAddress : inetAddresses) { for (String inetAddress : inetAddresses) {
String message = String.format(Locale.ROOT, "Expected address %s to be allowed", inetAddress); String message = String.format(Locale.ROOT, "Expected address %s to be allowed", inetAddress);
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(true)); assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(true));
} }
} }
private void assertAddressIsDenied(IPFilteringN2NAuthenticator ipFilteringN2NAuthenticator, String ... inetAddresses) { private void assertAddressIsDenied(String ... inetAddresses) {
for (String inetAddress : inetAddresses) { for (String inetAddress : inetAddresses) {
String message = String.format(Locale.ROOT, "Expected address %s to be denied", inetAddress); String message = String.format(Locale.ROOT, "Expected address %s to be denied", inetAddress);
assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(false)); assertThat(message, ipFilteringN2NAuthenticator.authenticate(NULL_PRINCIPAL, InetAddresses.forString(inetAddress), 1024), is(false));

View File

@ -7,56 +7,48 @@ package org.elasticsearch.shield.n2n;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import org.elasticsearch.common.os.OsUtils;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.shield.plugin.SecurityPlugin; import org.elasticsearch.shield.test.ShieldIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.net.URL; import java.net.URL;
import java.util.Locale; import java.util.Locale;
import static org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
/** // no client nodes, no transport nodes, as they all get rejected on network connections
* @ClusterScope(scope = Scope.SUITE, numDataNodes = 1, numClientNodes = 0, transportClientRatio = 0.0)
*/ public class IpFilteringIntegrationTests extends ShieldIntegrationTest {
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numDataNodes = 1, transportClientRatio = 0.0, numClientNodes = 0)
@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch-shield/issues/36") private static final String CONFIG_IPFILTER_DENY_ALL = "deny: all\n";
public class IpFilteringIntegrationTests extends ElasticsearchIntegrationTest {
@Override @Override
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
ImmutableSettings.Builder builder = settingsBuilder() File folder = newFolder();
.put(super.nodeSettings(nodeOrdinal))
.put("discovery.zen.ping.multicast.ping.enabled", false)
.put("node.mode", "network")
// todo http tests fail without an explicit IP (needs investigation)
.put("network.host", randomBoolean() ? "127.0.0.1" : "::1")
.put("plugin.types", SecurityPlugin.class.getName());
//.put("shield.n2n.file", configFile.getPath())
if (OsUtils.MAC) { return settingsBuilder()
builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1"); .put(super.nodeSettings(nodeOrdinal))
} .put("shield.n2n.file", writeFile(folder, "ip_filter.yml", CONFIG_IPFILTER_DENY_ALL))
return builder.build(); .build();
} }
@Test(expected = SocketException.class) @Test(expected = SocketException.class)
public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaHttp() throws Exception { public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaHttp() throws Exception {
TransportAddress transportAddress = internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddress(); TransportAddress transportAddress = internalCluster().getDataNodeInstance(HttpServerTransport.class).boundAddress().boundAddress();
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
String url = String.format(Locale.ROOT, "http://%s:%s/", InetAddresses.toUriString(inetSocketTransportAddress.address().getAddress()), inetSocketTransportAddress.address().getPort()); String url = String.format(Locale.ROOT, "http://%s:%s/", InetAddresses.toUriString(inetSocketTransportAddress.address().getAddress()), inetSocketTransportAddress.address().getPort());
@ -67,17 +59,22 @@ public class IpFilteringIntegrationTests extends ElasticsearchIntegrationTest {
logger.info("HTTP connection response code [{}]", connection.getResponseCode()); logger.info("HTTP connection response code [{}]", connection.getResponseCode());
} }
@Ignore("Need to investigate further, why this does not fail")
@Test(expected = SocketException.class) @Test(expected = SocketException.class)
public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaTransportClient() throws Exception { public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaTransportClient() throws Exception {
InetSocketTransportAddress transportAddress = (InetSocketTransportAddress) internalCluster().getDataNodeInstance(Transport.class).boundAddress().boundAddress(); InetSocketTransportAddress transportAddress = (InetSocketTransportAddress) internalCluster().getDataNodeInstance(Transport.class).boundAddress().boundAddress();
// TODO: This works and I do not understand why, telnet breaks... try (Socket socket = new Socket()) {
Socket socket = new Socket(transportAddress.address().getAddress(), transportAddress.address().getPort()); logger.info("Connecting to {}", transportAddress.address());
socket.getOutputStream().write("foo".getBytes(Charsets.UTF_8)); socket.connect(transportAddress.address(), 500);
socket.getOutputStream().flush();
socket.getInputStream().close();
assertThat(socket.isConnected(), is(true)); assertThat(socket.isConnected(), is(true));
socket.close(); try (OutputStream os = socket.getOutputStream()) {
os.write("foo".getBytes(Charsets.UTF_8));
os.flush();
}
try (InputStream is = socket.getInputStream()) {
is.read();
}
}
} }
} }

View File

@ -7,101 +7,23 @@ package org.elasticsearch.shield.plugin;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.common.os.OsUtils; import org.elasticsearch.shield.test.ShieldIntegrationTest;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.transport.SecuredTransportService;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.transport.TransportModule;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
/** public class ShieldPluginTests extends ShieldIntegrationTest {
*
*/
@ClusterScope(scope = Scope.SUITE, numDataNodes = 2, randomDynamicTemplates = false)
@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch-shield/issues/36")
public class ShieldPluginTests extends ElasticsearchIntegrationTest {
@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();
@Override
protected Settings nodeSettings(int nodeOrdinal) {
File folder = newFolder();
ImmutableSettings.Builder builder = ImmutableSettings.builder()
.put("plugin.types", SecurityPlugin.class.getName())
.put(super.nodeSettings(nodeOrdinal))
.put("shield.audit.enabled", true)
.put("shield.authc.esusers.files.users", copyFile(folder, "users"))
.put("shield.authc.esusers.files.users_roles", copyFile(folder, "users_roles"))
.put("shield.authz.store.files.roles", copyFile(folder, "roles.yml"))
.put("shield.n2n.file", copyFile(folder, "ip_filter.yml"))
.put(TransportModule.TRANSPORT_SERVICE_TYPE_KEY, SecuredTransportService.class.getName())
// for the test internal node clients
.put("request.headers.Authorization", basicAuthHeaderValue("test_user", "changeme".toCharArray()));
if (OsUtils.MAC) {
builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1");
}
return builder.build();
}
@Override
protected Settings transportClientSettings() {
return ImmutableSettings.builder()
.put("request.headers.Authorization", basicAuthHeaderValue("test_user", "changeme".toCharArray()))
.build();
}
@Test @Test
@TestLogging("_root:INFO,plugins.PluginsService:TRACE")
public void testThatPluginIsLoaded() { public void testThatPluginIsLoaded() {
logger.info("--> Getting nodes info"); logger.info("--> Getting nodes info");
NodesInfoResponse nodeInfos = internalCluster().transportClient().admin().cluster().prepareNodesInfo().get(); NodesInfoResponse nodeInfos = internalCluster().transportClient().admin().cluster().prepareNodesInfo().get();
logger.info("--> Checking nodes info"); logger.info("--> Checking nodes info that shield plugin is loaded");
for (NodeInfo nodeInfo : nodeInfos.getNodes()) { for (NodeInfo nodeInfo : nodeInfos.getNodes()) {
assertThat(nodeInfo.getPlugins().getInfos(), hasSize(1)); assertThat(nodeInfo.getPlugins().getInfos(), hasSize(1));
assertThat(nodeInfo.getPlugins().getInfos().get(0).getName(), is(SecurityPlugin.NAME)); assertThat(nodeInfo.getPlugins().getInfos().get(0).getName(), is(SecurityPlugin.NAME));
} }
} }
private File newFolder() {
try {
return tmpFolder.newFolder();
} catch (IOException ioe) {
logger.error("could not create temporary folder", ioe);
fail("could not create temporary folder");
return null;
}
}
private String copyFile(File folder, String name) {
Path file = folder.toPath().resolve(name);
try {
Files.copy(getClass().getResourceAsStream(name), file);
} catch (IOException ioe) {
logger.error("could not copy temporary configuration file [" + name + "]", ioe);
fail("could not copy temporary configuration file [" + name + "]");
}
return file.toAbsolutePath().toString();
}
} }

View File

@ -0,0 +1,167 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.test;
import com.google.common.base.Charsets;
import com.google.common.net.InetAddresses;
import org.apache.lucene.util.AbstractRandomizedTest;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.os.OsUtils;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.shield.plugin.SecurityPlugin;
import org.elasticsearch.shield.transport.netty.NettySecuredTransport;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportModule;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@Ignore
@AbstractRandomizedTest.Integration
@ClusterScope(scope = Scope.SUITE, numDataNodes = 1, numClientNodes = 0)
public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest {
private static final String DEFAULT_USER_NAME = "test_user";
private static final String DEFAULT_PASSWORD = "changeme";
private static final String DEFAULT_ROLE = "user";
public static final String CONFIG_IPFILTER_ALLOW_ALL = "allow: all\n";
public static final String CONFIG_STANDARD_USER = DEFAULT_USER_NAME + ":{plain}" + DEFAULT_PASSWORD + "\n";
public static final String CONFIG_STANDARD_USER_ROLES = DEFAULT_USER_NAME + ":" + DEFAULT_ROLE + "\n";
public static final String CONFIG_ROLE_ALLOW_ALL = "user:\n" +
" cluster: ALL\n" +
" indices:\n" +
" '.*': ALL\n";
@ClassRule
public static TemporaryFolder tmpFolder = new TemporaryFolder();
@Override
protected Settings nodeSettings(int nodeOrdinal) {
File folder = newFolder();
ImmutableSettings.Builder builder = ImmutableSettings.builder()
.put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword().toCharArray()))
.put("discovery.zen.ping.multicast.enabled", false)
.put("discovery.type", "zen")
.put("node.mode", "network")
.put("plugin.types", SecurityPlugin.class.getName())
.put("shield.authc.esusers.files.users", writeFile(folder, "users", CONFIG_STANDARD_USER))
.put("shield.authc.esusers.files.users_roles", writeFile(folder, "users_roles", CONFIG_STANDARD_USER_ROLES))
.put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", CONFIG_ROLE_ALLOW_ALL))
.put("shield.n2n.file", writeFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL))
.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode"))
.put("shield.audit.enabled", true);
if (OsUtils.MAC) {
builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1");
}
return builder.build();
}
@Override
protected Settings transportClientSettings() {
return ImmutableSettings.builder()
.put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword().toCharArray()))
.put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
.put("node.mode", "network")
.put("discovery.zen.ping.multicast.ping.enabled", false)
.putArray("discovery.zen.ping.unicast.hosts", getUnicastHostAddress())
.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"))
.build();
}
protected String writeFile(File folder, String name, String content) {
Path file = folder.toPath().resolve(name);
try {
com.google.common.io.Files.write(content.getBytes(Charsets.UTF_8), file.toFile());
} catch (IOException e) {
throw new ElasticsearchException("Error writing file in test", e);
}
return file.toFile().getAbsolutePath();
}
protected String getUnicastHostAddress() {
TransportAddress transportAddress = internalCluster().getDataNodeInstance(Transport.class).boundAddress().publishAddress();
assertThat(transportAddress, instanceOf(InetSocketTransportAddress.class));
InetSocketTransportAddress address = (InetSocketTransportAddress) transportAddress;
return InetAddresses.toAddrString(address.address().getAddress()) + ":" + address.address().getPort();
}
protected String getClientUsername() {
return DEFAULT_USER_NAME;
};
protected String getClientPassword() {
return DEFAULT_PASSWORD;
}
protected Settings getSSLSettingsForStore(String resourcePathToStore, String password) {
File store;
try {
store = new File(getClass().getResource(resourcePathToStore).toURI());
assertThat(store.exists(), is(true));
} catch (Exception e) {
throw new RuntimeException(e);
}
ImmutableSettings.Builder builder = settingsBuilder()
.put("shield.transport.ssl", true)
.put("shield.transport.ssl.keystore", store.getPath())
.put("shield.transport.ssl.keystore_password", password)
.put("shield.transport.ssl.truststore", store.getPath())
.put("shield.transport.ssl.truststore_password", password)
.put("shield.http.ssl", true)
.put("shield.http.ssl.require.client.auth", false)
.put("shield.http.ssl.keystore", store.getPath())
.put("shield.http.ssl.keystore_password", password)
.put("shield.http.ssl.truststore", store.getPath())
.put("shield.http.ssl.truststore_password", password);
return builder.build();
}
protected File newFolder() {
try {
return tmpFolder.newFolder();
} catch (IOException ioe) {
logger.error("could not create temporary folder", ioe);
fail("could not create temporary folder");
return null;
}
}
protected String copyFile(File folder, String name) {
Path file = folder.toPath().resolve(name);
try {
Files.copy(getClass().getResourceAsStream(name), file);
} catch (IOException ioe) {
logger.error("could not copy temporary configuration file [" + name + "]", ioe);
fail("could not copy temporary configuration file [" + name + "]");
}
return file.toAbsolutePath().toString();
}
}

View File

@ -5,117 +5,76 @@
*/ */
package org.elasticsearch.shield.transport.ssl; package org.elasticsearch.shield.transport.ssl;
import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.google.common.net.InetAddresses;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.os.OsUtils; import org.elasticsearch.common.net.InetAddresses;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder; import org.elasticsearch.node.NodeBuilder;
import org.elasticsearch.shield.plugin.SecurityPlugin; import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.shield.test.ShieldIntegrationTest;
import org.elasticsearch.shield.transport.netty.NettySecuredTransport; import org.elasticsearch.shield.transport.netty.NettySecuredTransport;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportModule; import org.elasticsearch.transport.TransportModule;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import javax.net.ssl.*; import javax.net.ssl.*;
import java.io.File;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.Locale; import java.util.Locale;
import static org.apache.lucene.util.LuceneTestCase.AwaitsFix; import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
@ClusterScope(scope = Scope.SUITE, numDataNodes = 1, transportClientRatio = 0.0, numClientNodes = 0) public class SslIntegrationTests extends ShieldIntegrationTest {
@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch-shield/issues/36")
public class SslIntegrationTests extends ElasticsearchIntegrationTest {
@ClassRule
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
private static File ipFilterFile;
@BeforeClass
public static void writeAllowAllIpFilterFile() throws Exception {
ipFilterFile = temporaryFolder.newFile();
Files.write("allow: all\n".getBytes(com.google.common.base.Charsets.UTF_8), ipFilterFile);
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
File testnodeStore;
try {
testnodeStore = new File(getClass().getResource("certs/simple/testnode.jks").toURI());
assertThat(testnodeStore.exists(), is(true));
} catch (Exception e) {
throw new RuntimeException(e);
}
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
.put("discovery.zen.ping.multicast.ping.enabled", false)
//
.put("shield.authz.file.roles", "not/existing")
// needed to ensure that netty transport is started
.put("node.mode", "network")
.put("shield.transport.ssl", true)
.put("shield.transport.ssl.keystore", testnodeStore.getPath())
.put("shield.transport.ssl.keystore_password", "testnode")
.put("shield.transport.ssl.truststore", testnodeStore.getPath())
.put("shield.transport.ssl.truststore_password", "testnode")
.put("shield.http.ssl", true)
.put("shield.http.ssl.require.client.auth", false)
.put("shield.http.ssl.keystore", testnodeStore.getPath())
.put("shield.http.ssl.keystore_password", "testnode")
.put("shield.http.ssl.truststore", testnodeStore.getPath())
.put("shield.http.ssl.truststore_password", "testnode")
// SSL SETUP
.put("plugin.types", SecurityPlugin.class.getName())
.put("shield.n2n.file", ipFilterFile.getPath());
if (OsUtils.MAC) {
builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1");
}
return builder.build();
}
@Test @Test
@TestLogging("_root:INFO,org.elasticsearch.test:TRACE, org.elasticsearch.client.transport:DEBUG,org.elasticsearch.shield:TRACE") public void testThatInternallyCreatedTransportClientCanConnect() throws Exception {
public void testThatTransportClientCanConnectToNodeViaSsl() throws Exception { Client transportClient = internalCluster().transportClient();
TransportClient transportClient = new TransportClient(getSettings("transport_client").build(), false);
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
transportClient.addTransportAddress(transportAddress);
assertGreenClusterState(transportClient); assertGreenClusterState(transportClient);
} }
@Test(expected = ElasticsearchSSLException.class) @Test
@TestLogging("_root:INFO,org.elasticsearch.client.transport:DEBUG") public void testThatProgrammaticallyCreatedTransportClientCanConnect() throws Exception {
public void testThatUnconfiguredCipchersAreRejected() { Settings settings = settingsBuilder()
// some randomly taken ciphers from SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites() .put(transportClientSettings())
// could be really randomized .put("name", "programmatic_transport_client_")
Settings customSettings = getSettings("transport_client").put("shield.transport.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}).build(); .put("cluster.name", internalCluster().getClusterName())
.build();
TransportClient transportClient = new TransportClient(customSettings); try (TransportClient transportClient = new TransportClient(settings, false)) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
transportClient.addTransportAddress(transportAddress);
assertGreenClusterState(transportClient);
}
try (TransportClient transportClient = new TransportClient(settings, true)) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
transportClient.addTransportAddress(transportAddress);
assertGreenClusterState(transportClient);
}
}
// no SSL exception as this is the exception is returned when connecting
@Test(expected = NoNodeAvailableException.class)
public void testThatUnconfiguredCipchersAreRejected() {
TransportClient transportClient = new TransportClient(settingsBuilder()
.put(transportClientSettings())
.put("name", "programmatic_transport_client")
.put("cluster.name", internalCluster().getClusterName())
.putArray("shield.transport.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"})
.build());
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress(); TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress();
transportClient.addTransportAddress(transportAddress); transportClient.addTransportAddress(transportAddress);
@ -124,9 +83,19 @@ public class SslIntegrationTests extends ElasticsearchIntegrationTest {
} }
@Test @Test
@TestLogging("_root:DEBUG")
public void testConnectNodeWorks() throws Exception { public void testConnectNodeWorks() throws Exception {
try (Node node = NodeBuilder.nodeBuilder().settings(getSettings("ssl_node")).node().start()) { Settings settings = settingsBuilder()
.put("name", "programmatic_node")
.put("cluster.name", internalCluster().getClusterName())
.put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword().toCharArray()))
.put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
.put(getSSLSettingsForStore("certs/simple/testclient.jks", "testclient"))
.build();
try (Node node = NodeBuilder.nodeBuilder().settings(settings).node()) {
try (Client client = node.client()) { try (Client client = node.client()) {
assertGreenClusterState(client); assertGreenClusterState(client);
} }
@ -135,34 +104,30 @@ public class SslIntegrationTests extends ElasticsearchIntegrationTest {
@Test @Test
public void testConnectNodeClientWorks() throws Exception { public void testConnectNodeClientWorks() throws Exception {
// no multicast, good old discovery Settings settings = settingsBuilder()
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress(); .put("name", "programmatic_node_client")
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); .put("cluster.name", internalCluster().getClusterName())
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; .put("node.mode", "network")
Settings.Builder settingsBuilder = getSettings("node_client")
.put("node.client", true)
.put("discovery.zen.ping.multicast.ping.enabled", false)
.put("discovery.zen.ping.unicast.hosts", inetSocketTransportAddress.address().getHostString() + ":" + inetSocketTransportAddress.address().getPort());
try (Node node = NodeBuilder.nodeBuilder().settings(settingsBuilder).node().start()) { .put("discovery.zen.ping.multicast.enabled", false)
.put("discovery.type", "zen")
.putArray("discovery.zen.ping.unicast.hosts", getUnicastHostAddress())
.put("request.headers.Authorization", basicAuthHeaderValue(getClientUsername(), getClientPassword().toCharArray()))
.put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
.put("shield.n2n.file", writeFile(newFolder(), "ip_filter.yml", ShieldIntegrationTest.CONFIG_IPFILTER_ALLOW_ALL))
.put(getSSLSettingsForStore("certs/simple/testclient.jks", "testclient"))
.build();
try (Node node = NodeBuilder.nodeBuilder().settings(settings).client(true).node()) {
try (Client client = node.client()) { try (Client client = node.client()) {
assertGreenClusterState(client); assertGreenClusterState(client);
} }
} }
} }
@Test(expected = ElasticsearchSSLException.class)
public void testConnectNodeFailsWithWrongCipher() throws Exception {
Settings customSettings = getSettings("ssl_node").put("shield.transport.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}).build();
NodeBuilder.nodeBuilder().settings(customSettings).node().start();
}
@Test(expected = ElasticsearchSSLException.class)
public void testConnectNodeClientFailsWithWrongCipher() throws Exception {
Settings customSettings = getSettings("ssl_node").put("node.client", true).put("shield.transport.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}).build();
NodeBuilder.nodeBuilder().settings(customSettings).node().start();
}
@Test @Test
public void testThatConnectionToHTTPWorks() throws Exception { public void testThatConnectionToHTTPWorks() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[]{ TrustManager[] trustAllCerts = new TrustManager[]{
@ -206,36 +171,9 @@ public class SslIntegrationTests extends ElasticsearchIntegrationTest {
assertThat(data, containsString("You Know, for Search")); assertThat(data, containsString("You Know, for Search"));
} }
private ImmutableSettings.Builder getSettings(String name) {
File testClientKeyStore;
File testClientTrustStore;
try {
testClientKeyStore = new File(getClass().getResource("certs/simple/testclient.jks").toURI());
testClientTrustStore = new File(getClass().getResource("certs/simple/testclient.jks").toURI());
} catch (Exception e) {
throw new RuntimeException(e);
}
assertThat(testClientKeyStore.exists(), is(true));
assertThat(testClientTrustStore.exists(), is(true));
return ImmutableSettings.settingsBuilder()
.put("node.name", name)
.put("plugins.load_classpath_plugins", false)
.put("shield.transport.ssl", true)
.put("shield.transport.ssl.keystore", testClientKeyStore.getPath())
.put("shield.transport.ssl.keystore_password", "testclient")
.put("shield.transport.ssl.truststore", testClientTrustStore .getPath())
.put("shield.transport.ssl.truststore_password", "testclient")
.put("discovery.zen.ping.multicast.ping.enabled", false)
.put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
.put("shield.n2n.file", ipFilterFile.getPath())
.put("cluster.name", internalCluster().getClusterName());
}
private void assertGreenClusterState(Client client) { private void assertGreenClusterState(Client client) {
ClusterHealthResponse clusterHealthResponse = client.admin().cluster().prepareHealth().get(); ClusterHealthResponse clusterHealthResponse = client.admin().cluster().prepareHealth().get();
assertNoTimeout(clusterHealthResponse); assertNoTimeout(clusterHealthResponse);
assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN)); assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN));
} }
} }

View File

@ -6,22 +6,15 @@
package org.elasticsearch.shield.transport.ssl; package org.elasticsearch.shield.transport.ssl;
import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.base.Charsets; import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.os.OsUtils;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.shield.plugin.SecurityPlugin; import org.elasticsearch.shield.test.ShieldIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import javax.net.ssl.*; import javax.net.ssl.*;
import java.io.File; import java.io.File;
@ -33,15 +26,16 @@ import java.security.KeyStore;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Locale; import java.util.Locale;
import static org.apache.lucene.util.LuceneTestCase.AwaitsFix; import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
/** /**
* *
*/ */
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numDataNodes = 1, transportClientRatio = 0.0, numClientNodes = 0) @ClusterScope(scope = Scope.SUITE, numDataNodes = 1, numClientNodes = 0)
@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch-shield/issues/36") public class SslRequireAuthTests extends ShieldIntegrationTest {
public class SslRequireAuthTests extends ElasticsearchIntegrationTest {
public static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() { public static final HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
@Override @Override
@ -50,54 +44,22 @@ public class SslRequireAuthTests extends ElasticsearchIntegrationTest {
} }
}; };
@ClassRule @Override
public static TemporaryFolder temporaryFolder = new TemporaryFolder(); protected Settings nodeSettings(int nodeOrdinal) {
return settingsBuilder()
private static File ipFilterFile; .put(super.nodeSettings(nodeOrdinal))
.put(getSSLSettingsForStore("certs/simple/testnode.jks", "testnode"))
@BeforeClass .put("shield.transport.ssl.require.client.auth", true)
public static void writeAllowAllIpFilterFile() throws Exception { .put("shield.http.ssl.require.client.auth", true)
ipFilterFile = temporaryFolder.newFile(); .build();
Files.write("allow: all\n".getBytes(com.google.common.base.Charsets.UTF_8), ipFilterFile);
} }
@Override @Override
protected Settings nodeSettings(int nodeOrdinal) { protected Settings transportClientSettings() {
File testnodeStore; return ImmutableSettings.builder()
try { .put(super.transportClientSettings())
testnodeStore = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI()); .put(getSSLSettingsForStore("certs/simple/testclient.jks", "testclient"))
assertThat(testnodeStore.exists(), is(true)); .build();
} catch (Exception e) {
throw new RuntimeException(e);
}
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
.put("discovery.zen.ping.multicast.ping.enabled", false)
// prevents exception until parsing has been fixed in PR
.put("shield.authz.file.roles", "not/existing")
// needed to ensure that netty transport is started
.put("node.mode", "network")
.put("shield.transport.ssl", true)
.put("shield.transport.ssl.require.client.auth", true)
.put("shield.transport.ssl.keystore", testnodeStore.getPath())
.put("shield.transport.ssl.keystore_password", "testnode")
.put("shield.transport.ssl.truststore", testnodeStore.getPath())
.put("shield.transport.ssl.truststore_password", "testnode")
.put("shield.http.ssl", true)
.put("shield.http.ssl.require.client.auth", true)
.put("shield.http.ssl.keystore", testnodeStore.getPath())
.put("shield.http.ssl.keystore_password", "testnode")
.put("shield.http.ssl.truststore", testnodeStore.getPath())
.put("shield.http.ssl.truststore_password", "testnode")
.put("plugin.types", SecurityPlugin.class.getName())
.put("shield.n2n.file", ipFilterFile.getPath());
if (OsUtils.MAC) {
builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1");
}
return builder.build();
} }
@ -131,7 +93,6 @@ public class SslRequireAuthTests extends ElasticsearchIntegrationTest {
} }
@Test @Test
@TestLogging("_root:DEBUG")
public void testThatConnectionToHTTPWorks() throws Exception { public void testThatConnectionToHTTPWorks() throws Exception {
File store = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI()); File store = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI());