diff --git a/pom.xml b/pom.xml
index c7eaff4560d..2b8c8271589 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,7 @@
512m
5
.local-${project.version}-execution-hints.log
+ false
@@ -119,6 +120,18 @@
2.1
test
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.5
+ test
+
+
+ org.codehaus.groovy
+ groovy-all
+ 2.3.2
+ test
+
diff --git a/src/test/java/org/elasticsearch/test/ShieldRestTests.java b/src/test/java/org/elasticsearch/test/ShieldRestTests.java
new file mode 100644
index 00000000000..183c731d174
--- /dev/null
+++ b/src/test/java/org/elasticsearch/test/ShieldRestTests.java
@@ -0,0 +1,168 @@
+/*
+ * 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.test;
+
+import com.carrotsearch.randomizedtesting.SysGlobals;
+import com.carrotsearch.randomizedtesting.annotations.Name;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+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.plugins.PluginsService;
+import org.elasticsearch.shield.plugin.ShieldPlugin;
+import org.elasticsearch.shield.transport.netty.NettySecuredTransport;
+import org.elasticsearch.test.rest.ElasticsearchRestTests;
+import org.elasticsearch.test.rest.RestTestCandidate;
+import org.elasticsearch.transport.TransportModule;
+import org.junit.AfterClass;
+import org.junit.ClassRule;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
+import static org.hamcrest.Matchers.is;
+
+/**
+ *
+ */
+public class ShieldRestTests extends ElasticsearchRestTests {
+
+ public static final int CHILD_JVM_ID = Integer.parseInt(System.getProperty(SysGlobals.CHILDVM_SYSPROP_JVM_ID, "0"));
+ public static final int BASE_PORT = 33000 + CHILD_JVM_ID * 100;
+ public static final String BASE_PORT_RANGE = BASE_PORT + "-" + (BASE_PORT+10) ;
+
+ protected static final boolean ENABLE_TRANSPORT_SSL = true;
+ protected static final boolean SHIELD_AUDIT_ENABLED = false;
+
+ protected static final String DEFAULT_USER_NAME = "test_user";
+ protected static final String DEFAULT_PASSWORD = "changeme";
+ protected 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";
+
+ static {
+ InternalTestCluster.DEFAULT_SETTINGS_SOURCE = new SettingsSource() {
+
+ @Override
+ public Settings node(int nodeOrdinal) {
+ File store;
+ try {
+ store = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI());
+ assertThat(store.exists(), is(true));
+ } catch (Exception e) {
+ throw new ElasticsearchException("Error reading test node cert", e);
+ }
+ String password = "testnode";
+
+ File folder = createFolder();
+
+ ImmutableSettings.Builder builder = ImmutableSettings.builder()
+ .put("request.headers.Authorization", basicAuthHeaderValue(DEFAULT_USER_NAME, DEFAULT_PASSWORD.toCharArray()))
+ .put("discovery.zen.ping.multicast.enabled", false)
+ .put("discovery.type", "zen")
+ .put("node.mode", "network")
+ .put("plugin.types", ShieldPlugin.class.getName())
+ .put("shield.authc.esusers.files.users", createFile(folder, "users", CONFIG_STANDARD_USER))
+ .put("shield.authc.esusers.files.users_roles", createFile(folder, "users_roles", CONFIG_STANDARD_USER_ROLES))
+ .put("shield.authz.store.files.roles", createFile(folder, "roles.yml", CONFIG_ROLE_ALLOW_ALL))
+ .put("shield.transport.n2n.ip_filter.file", createFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL))
+ .put("shield.transport.ssl", ENABLE_TRANSPORT_SSL)
+ .put("shield.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", false)
+ .put("transport.tcp.port", BASE_PORT_RANGE)
+ .putArray("discovery.zen.ping.unicast.hosts", "127.0.0.1:" + BASE_PORT, "127.0.0.1:" + (BASE_PORT + 1), "127.0.0.1:" + (BASE_PORT + 2), "127.0.0.1:" + (BASE_PORT + 3))
+ .put("shield.audit.enabled", SHIELD_AUDIT_ENABLED);
+
+ builder.put("network.host", "127.0.0.1");
+ if (OsUtils.MAC) {
+ builder.put("network.host", randomBoolean() ? "127.0.0.1" : "::1");
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ public Settings transportClient() {
+ File store;
+ String password = "testclient";
+ try {
+ store = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
+ assertThat(store.exists(), is(true));
+ } catch (Exception e) {
+ throw new ElasticsearchException("Error reading test client cert", e);
+ }
+
+ File folder = createFolder();
+
+ return ImmutableSettings.builder()
+ .put("request.headers.Authorization", basicAuthHeaderValue(DEFAULT_USER_NAME, DEFAULT_PASSWORD.toCharArray()))
+ .put(TransportModule.TRANSPORT_TYPE_KEY, NettySecuredTransport.class.getName())
+ .put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
+ .put("node.mode", "network")
+ .put("shield.transport.n2n.ip_filter.file", createFile(folder, "ip_filter.yml", CONFIG_IPFILTER_ALLOW_ALL))
+ .put("shield.transport.ssl", ENABLE_TRANSPORT_SSL)
+ .put("shield.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("cluster.name", internalCluster().getClusterName())
+ .build();
+ }
+ };
+ }
+
+ @ClassRule
+ public static TemporaryFolder tmpFolder = new TemporaryFolder();
+
+ @AfterClass
+ public static void cleanup() {
+ tmpFolder = null;
+ }
+
+ public ShieldRestTests(@Name("yaml") RestTestCandidate testCandidate) {
+ super(testCandidate);
+ }
+
+ @Override
+ protected Settings restClientSettings() {
+ return ImmutableSettings.builder()
+ .put("request.headers.Authorization", basicAuthHeaderValue(DEFAULT_USER_NAME, DEFAULT_PASSWORD.toCharArray())).build();
+ }
+
+ /* static helper methods for the global test class */
+ static File createFolder() {
+ try {
+ return tmpFolder.newFolder();
+ } catch (IOException ioe) {
+ fail("could not create temporary folder");
+ return null;
+ }
+ }
+
+ static String createFile(File folder, String name, String content) {
+ Path file = folder.toPath().resolve(name);
+ try {
+ 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();
+ }
+}