You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2016/12/20 10:48:34 UTC
[29/44] lucene-solr:jira/solr-9854: SOLR-9513: Generic Hadoop
authentication plugins,
GenericHadoopAuthPlugin and ConfigurableInternodeAuthHadoopPlugin
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/core/src/test/org/apache/solr/security/hadoop/TestImpersonationWithHadoopAuth.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/hadoop/TestImpersonationWithHadoopAuth.java b/solr/core/src/test/org/apache/solr/security/hadoop/TestImpersonationWithHadoopAuth.java
new file mode 100644
index 0000000..ed8397b
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/security/hadoop/TestImpersonationWithHadoopAuth.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.security.hadoop;
+
+import static org.apache.solr.security.HttpParamDelegationTokenPlugin.USER_PARAM;
+import static org.apache.solr.security.hadoop.ImpersonationUtil.*;
+
+import java.net.InetAddress;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.util.Constants;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.embedded.JettySolrRunner;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.security.HadoopAuthPlugin;
+import org.apache.solr.servlet.SolrRequestParsers;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestImpersonationWithHadoopAuth extends SolrCloudTestCase {
+ protected static final int NUM_SERVERS = 2;
+ private static final boolean defaultAddRequestHeadersToContext =
+ SolrRequestParsers.DEFAULT.isAddRequestHeadersToContext();
+
+ @SuppressWarnings("unchecked")
+ @BeforeClass
+ public static void setupClass() throws Exception {
+ assumeFalse("Hadoop does not work on Windows", Constants.WINDOWS);
+
+ InetAddress loopback = InetAddress.getLoopbackAddress();
+ Path securityJsonPath = TEST_PATH().resolve("security").resolve("hadoop_simple_auth_with_delegation.json");
+ String securityJson = new String(Files.readAllBytes(securityJsonPath), Charset.defaultCharset());
+
+ Map<String, Object> securityConfig = (Map<String, Object>)Utils.fromJSONString(securityJson);
+ Map<String, Object> authConfig = (Map<String, Object>)securityConfig.get("authentication");
+ Map<String,String> proxyUserConfigs = (Map<String,String>) authConfig
+ .getOrDefault(HadoopAuthPlugin.PROXY_USER_CONFIGS, new HashMap<>());
+ proxyUserConfigs.put("proxyuser.noGroups.hosts", "*");
+ proxyUserConfigs.put("proxyuser.anyHostAnyUser.hosts", "*");
+ proxyUserConfigs.put("proxyuser.anyHostAnyUser.groups", "*");
+ proxyUserConfigs.put("proxyuser.wrongHost.hosts", "1.1.1.1.1.1");
+ proxyUserConfigs.put("proxyuser.wrongHost.groups", "*");
+ proxyUserConfigs.put("proxyuser.noHosts.groups", "*");
+ proxyUserConfigs.put("proxyuser.localHostAnyGroup.hosts",
+ loopback.getCanonicalHostName() + "," + loopback.getHostName() + "," + loopback.getHostAddress());
+ proxyUserConfigs.put("proxyuser.localHostAnyGroup.groups", "*");
+ proxyUserConfigs.put("proxyuser.bogusGroup.hosts", "*");
+ proxyUserConfigs.put("proxyuser.bogusGroup.groups", "__some_bogus_group");
+ proxyUserConfigs.put("proxyuser.anyHostUsersGroup.groups", ImpersonationUtil.getUsersFirstGroup());
+ proxyUserConfigs.put("proxyuser.anyHostUsersGroup.hosts", "*");
+
+ authConfig.put(HadoopAuthPlugin.PROXY_USER_CONFIGS, proxyUserConfigs);
+
+ SolrRequestParsers.DEFAULT.setAddRequestHeadersToContext(true);
+ System.setProperty("collectionsHandler", ImpersonatorCollectionsHandler.class.getName());
+
+ configureCluster(NUM_SERVERS)// nodes
+ .withSecurityJson(Utils.toJSONString(securityConfig))
+ .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
+ .configure();
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ SolrRequestParsers.DEFAULT.setAddRequestHeadersToContext(defaultAddRequestHeadersToContext);
+ System.clearProperty("collectionsHandler");
+ }
+
+ private SolrClient newSolrClient() {
+ return new HttpSolrClient.Builder(
+ cluster.getJettySolrRunner(0).getBaseUrl().toString()).build();
+ }
+
+ @Test
+ public void testProxyNoConfigGroups() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("noGroups","bar"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ assertTrue(ex.getLocalizedMessage(), ex.getMessage().contains(getExpectedGroupExMsg("noGroups", "bar")));
+ }
+ }
+
+ @Test
+ public void testProxyWrongHost() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("wrongHost","bar"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ assertTrue(ex.getMessage().contains(getExpectedHostExMsg("wrongHost")));
+ }
+ }
+
+ @Test
+ public void testProxyNoConfigHosts() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("noHosts","bar"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ assertTrue(ex.getMessage().contains(getExpectedHostExMsg("noHosts")));
+ }
+ }
+
+ @Test
+ public void testProxyValidateAnyHostAnyUser() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("anyHostAnyUser", "bar"));
+ assertTrue(ImpersonatorCollectionsHandler.called.get());
+ }
+ }
+
+ @Test
+ public void testProxyInvalidProxyUser() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ // wrong direction, should fail
+ solrClient.request(getProxyRequest("bar","anyHostAnyUser"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ assertTrue(ex.getMessage().contains(getExpectedGroupExMsg("bar", "anyHostAnyUser")));
+ }
+ }
+
+ @Test
+ public void testProxyValidateHost() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("localHostAnyGroup", "bar"));
+ assertTrue(ImpersonatorCollectionsHandler.called.get());
+ }
+ }
+
+ @Test
+ public void testProxyValidateGroup() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("anyHostUsersGroup", System.getProperty("user.name")));
+ assertTrue(ImpersonatorCollectionsHandler.called.get());
+ }
+ }
+
+ @Test
+ public void testProxyInvalidGroup() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("bogusGroup","bar"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ assertTrue(ex.getMessage().contains(getExpectedGroupExMsg("bogusGroup", "bar")));
+ }
+ }
+
+ @Test
+ public void testProxyNullProxyUser() throws Exception {
+ try (SolrClient solrClient = newSolrClient()) {
+ solrClient.request(getProxyRequest("","bar"));
+ fail("Expected RemoteSolrException");
+ }
+ catch (HttpSolrClient.RemoteSolrException ex) {
+ // this exception is specific to our implementation, don't check a specific message.
+ }
+ }
+
+ @Test
+ @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")
+ public void testForwarding() throws Exception {
+ String collectionName = "forwardingCollection";
+
+ // create collection
+ CollectionAdminRequest.Create create = CollectionAdminRequest.createCollection(collectionName, "conf1",
+ 1, 1);
+ try (SolrClient solrClient = newSolrClient()) {
+ create.process(solrClient);
+ }
+
+ // try a command to each node, one of them must be forwarded
+ for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
+ HttpSolrClient client =
+ new HttpSolrClient.Builder(jetty.getBaseUrl().toString() + "/" + collectionName).build();
+ try {
+ ModifiableSolrParams params = new ModifiableSolrParams();
+ params.set("q", "*:*");
+ params.set(USER_PARAM, "user");
+ client.query(params);
+ } finally {
+ client.close();
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/core/src/test/org/apache/solr/security/hadoop/TestSolrCloudWithHadoopAuthPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/hadoop/TestSolrCloudWithHadoopAuthPlugin.java b/solr/core/src/test/org/apache/solr/security/hadoop/TestSolrCloudWithHadoopAuthPlugin.java
new file mode 100644
index 0000000..960fd9a
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/security/hadoop/TestSolrCloudWithHadoopAuthPlugin.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.security.hadoop;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.lucene.util.Constants;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.AbstractDistribZkTestBase;
+import org.apache.solr.cloud.KerberosTestServices;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestSolrCloudWithHadoopAuthPlugin extends SolrCloudTestCase {
+ protected static final int NUM_SERVERS = 1;
+ protected static final int NUM_SHARDS = 1;
+ protected static final int REPLICATION_FACTOR = 1;
+ private static KerberosTestServices kerberosTestServices;
+
+ @BeforeClass
+ public static void setupClass() throws Exception {
+ assumeFalse("Hadoop does not work on Windows", Constants.WINDOWS);
+ assumeFalse("FIXME: SOLR-8182: This test fails under Java 9", Constants.JRE_IS_MINIMUM_JAVA9);
+
+ setupMiniKdc();
+
+ configureCluster(NUM_SERVERS)// nodes
+ .withSecurityJson(TEST_PATH().resolve("security").resolve("hadoop_kerberos_config.json"))
+ .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
+ .configure();
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ System.clearProperty("java.security.auth.login.config");
+ System.clearProperty("solr.kerberos.principal");
+ System.clearProperty("solr.kerberos.keytab");
+ System.clearProperty("solr.kerberos.name.rules");
+ System.clearProperty("solr.jaas.debug");
+ kerberosTestServices.stop();
+ kerberosTestServices = null;
+ }
+
+ private static void setupMiniKdc() throws Exception {
+ System.setProperty("solr.jaas.debug", "true");
+ String kdcDir = createTempDir()+File.separator+"minikdc";
+ String solrClientPrincipal = "solr";
+ File keytabFile = new File(kdcDir, "keytabs");
+ kerberosTestServices = KerberosTestServices.builder()
+ .withKdc(new File(kdcDir))
+ .withJaasConfiguration(solrClientPrincipal, keytabFile, "SolrClient")
+ .build();
+ String solrServerPrincipal = "HTTP/127.0.0.1";
+ kerberosTestServices.start();
+ kerberosTestServices.getKdc().createPrincipal(keytabFile, solrServerPrincipal, solrClientPrincipal);
+
+ String jaas = "SolrClient {\n"
+ + " com.sun.security.auth.module.Krb5LoginModule required\n"
+ + " useKeyTab=true\n"
+ + " keyTab=\"" + keytabFile.getAbsolutePath() + "\"\n"
+ + " storeKey=true\n"
+ + " useTicketCache=false\n"
+ + " doNotPrompt=true\n"
+ + " debug=true\n"
+ + " principal=\"" + solrClientPrincipal + "\";\n"
+ + "};";
+
+ String jaasFilePath = kdcDir+File.separator+"jaas-client.conf";
+ FileUtils.write(new File(jaasFilePath), jaas, StandardCharsets.UTF_8);
+ System.setProperty("java.security.auth.login.config", jaasFilePath);
+ System.setProperty("solr.kerberos.jaas.appname", "SolrClient"); // Get this app name from the jaas file
+
+ System.setProperty("solr.kerberos.principal", solrServerPrincipal);
+ System.setProperty("solr.kerberos.keytab", keytabFile.getAbsolutePath());
+ // Extracts 127.0.0.1 from HTTP/127.0.0.1@EXAMPLE.COM
+ System.setProperty("solr.kerberos.name.rules", "RULE:[1:$1@$0](.*EXAMPLE.COM)s/@.*//"
+ + "\nRULE:[2:$2@$0](.*EXAMPLE.COM)s/@.*//"
+ + "\nDEFAULT"
+ );
+ }
+
+ @Test
+ public void testBasics() throws Exception {
+ testCollectionCreateSearchDelete();
+ // sometimes run a second test e.g. to test collection create-delete-create scenario
+ if (random().nextBoolean()) testCollectionCreateSearchDelete();
+ }
+
+ protected void testCollectionCreateSearchDelete() throws Exception {
+ CloudSolrClient solrClient = cluster.getSolrClient();
+ String collectionName = "testkerberoscollection";
+
+ // create collection
+ CollectionAdminRequest.Create create = CollectionAdminRequest.createCollection(collectionName, "conf1",
+ NUM_SHARDS, REPLICATION_FACTOR);
+ create.process(solrClient);
+
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.setField("id", "1");
+ solrClient.add(collectionName, doc);
+ solrClient.commit(collectionName);
+
+ SolrQuery query = new SolrQuery();
+ query.setQuery("*:*");
+ QueryResponse rsp = solrClient.query(collectionName, query);
+ assertEquals(1, rsp.getResults().getNumFound());
+
+ CollectionAdminRequest.Delete deleteReq = CollectionAdminRequest.deleteCollection(collectionName);
+ deleteReq.process(solrClient);
+ AbstractDistribZkTestBase.waitForCollectionToDisappear(collectionName,
+ solrClient.getZkStateReader(), true, true, 330);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClientBuilderFactory.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClientBuilderFactory.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClientBuilderFactory.java
new file mode 100644
index 0000000..77c4a94
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClientBuilderFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.solrj.impl;
+
+import java.io.Closeable;
+import java.util.Optional;
+
+/**
+ * Factory interface for configuring {@linkplain SolrHttpClientBuilder}. This
+ * relies on the internal HttpClient implementation and is subject to
+ * change.
+ *
+ * @lucene.experimental
+ **/
+public interface HttpClientBuilderFactory extends Closeable {
+
+ /**
+ * This method configures the {@linkplain SolrHttpClientBuilder} by overriding the
+ * configuration of passed SolrHttpClientBuilder or as a new instance.
+ *
+ * @param builder The instance of the {@linkplain SolrHttpClientBuilder} which should
+ * by configured (optional).
+ * @return the {@linkplain SolrHttpClientBuilder}
+ */
+ public SolrHttpClientBuilder getHttpClientBuilder(Optional<SolrHttpClientBuilder> builder);
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
index 39cc2dc..7f3cf29 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientBuilder.java
@@ -21,6 +21,7 @@ import java.security.Principal;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
+import java.util.Optional;
import java.util.Set;
import javax.security.auth.login.AppConfigurationEntry;
@@ -46,7 +47,7 @@ import org.slf4j.LoggerFactory;
/**
* Kerberos-enabled SolrHttpClientBuilder
*/
-public class Krb5HttpClientBuilder {
+public class Krb5HttpClientBuilder implements HttpClientBuilderFactory {
public static final String LOGIN_CONFIG_PROP = "java.security.auth.login.config";
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -73,7 +74,12 @@ public class Krb5HttpClientBuilder {
public void close() {
HttpClientUtil.removeRequestInterceptor(bufferedEntityInterceptor);
}
-
+
+ @Override
+ public SolrHttpClientBuilder getHttpClientBuilder(Optional<SolrHttpClientBuilder> builder) {
+ return builder.isPresent() ? getBuilder(builder.get()) : getBuilder();
+ }
+
public SolrHttpClientBuilder getBuilder(SolrHttpClientBuilder builder) {
if (System.getProperty(LOGIN_CONFIG_PROP) != null) {
String configValue = System.getProperty(LOGIN_CONFIG_PROP);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
index 5ebdfb7..81e1f22 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
@@ -28,6 +28,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Random;
import java.util.SortedMap;
import java.util.concurrent.Callable;
@@ -68,6 +69,7 @@ public class MiniSolrCloudCluster {
" <str name=\"shareSchema\">${shareSchema:false}</str>\n" +
" <str name=\"configSetBaseDir\">${configSetBaseDir:configsets}</str>\n" +
" <str name=\"coreRootDirectory\">${coreRootDirectory:.}</str>\n" +
+ " <str name=\"collectionsHandler\">${collectionsHandler:solr.CollectionsHandler}</str>\n" +
"\n" +
" <shardHandlerFactory name=\"shardHandlerFactory\" class=\"HttpShardHandlerFactory\">\n" +
" <str name=\"urlScheme\">${urlScheme:}</str>\n" +
@@ -180,8 +182,30 @@ public class MiniSolrCloudCluster {
*
* @throws Exception if there was an error starting the cluster
*/
- public MiniSolrCloudCluster(int numServers, Path baseDir, String solrXml, JettyConfig jettyConfig, ZkTestServer zkTestServer) throws Exception {
+ public MiniSolrCloudCluster(int numServers, Path baseDir, String solrXml, JettyConfig jettyConfig,
+ ZkTestServer zkTestServer) throws Exception {
+ this(numServers, baseDir, solrXml, jettyConfig, zkTestServer, Optional.empty());
+ }
+ /**
+ * Create a MiniSolrCloudCluster.
+ * Note - this constructor visibility is changed to package protected so as to
+ * discourage its usage. Ideally *new* functionality should use {@linkplain SolrCloudTestCase}
+ * to configure any additional parameters.
+ *
+ * @param numServers number of Solr servers to start
+ * @param baseDir base directory that the mini cluster should be run from
+ * @param solrXml solr.xml file to be uploaded to ZooKeeper
+ * @param jettyConfig Jetty configuration
+ * @param zkTestServer ZkTestServer to use. If null, one will be created
+ * @param securityJson A string representation of security.json file (optional).
+ *
+ * @throws Exception if there was an error starting the cluster
+ */
+ MiniSolrCloudCluster(int numServers, Path baseDir, String solrXml, JettyConfig jettyConfig,
+ ZkTestServer zkTestServer, Optional<String> securityJson) throws Exception {
+
+ Objects.requireNonNull(securityJson);
this.baseDir = Objects.requireNonNull(baseDir);
this.jettyConfig = Objects.requireNonNull(jettyConfig);
@@ -202,6 +226,9 @@ public class MiniSolrCloudCluster {
if (jettyConfig.sslConfig != null && jettyConfig.sslConfig.isSSLMode()) {
zkClient.makePath("/solr" + ZkStateReader.CLUSTER_PROPS, "{'urlScheme':'https'}".getBytes(StandardCharsets.UTF_8), true);
}
+ if (securityJson.isPresent()) { // configure Solr security
+ zkClient.makePath("/solr/security.json", securityJson.get().getBytes(Charset.defaultCharset()), true);
+ }
}
// tell solr to look in zookeeper for solr.xml
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a1a8b286/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
index 9cc4a22..34dc8ac 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
@@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
@@ -90,6 +91,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
private final Path baseDir;
private String solrxml = MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML;
private JettyConfig jettyConfig = buildJettyConfig("/solr");
+ private Optional<String> securityJson = Optional.empty();
private List<Config> configs = new ArrayList<>();
private Map<String, String> clusterProperties = new HashMap<>();
@@ -133,6 +135,32 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
}
/**
+ * Configure the specified security.json for the {@linkplain MiniSolrCloudCluster}
+ *
+ * @param securityJson The path specifying the security.json file
+ * @return the instance of {@linkplain Builder}
+ */
+ public Builder withSecurityJson(Path securityJson) {
+ try {
+ this.securityJson = Optional.of(new String(Files.readAllBytes(securityJson), Charset.defaultCharset()));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return this;
+ }
+
+ /**
+ * Configure the specified security.json for the {@linkplain MiniSolrCloudCluster}
+ *
+ * @param securityJson The string specifying the security.json configuration
+ * @return the instance of {@linkplain Builder}
+ */
+ public Builder withSecurityJson(String securityJson) {
+ this.securityJson = Optional.of(securityJson);
+ return this;
+ }
+
+ /**
* Upload a collection config before tests start
* @param configName the config name
* @param configPath the path to the config files
@@ -157,7 +185,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
* @throws Exception if an error occurs on startup
*/
public void configure() throws Exception {
- cluster = new MiniSolrCloudCluster(nodeCount, baseDir, solrxml, jettyConfig);
+ cluster = new MiniSolrCloudCluster(nodeCount, baseDir, solrxml, jettyConfig, null, securityJson);
CloudSolrClient client = cluster.getSolrClient();
for (Config config : configs) {
((ZkClientClusterStateProvider)client.getClusterStateProvider()).uploadConfig(config.path, config.name);