You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by an...@apache.org on 2015/05/22 08:26:10 UTC
svn commit: r1681001 - in /lucene/dev/trunk: lucene/tools/junit4/ solr/
solr/core/src/java/org/apache/solr/security/
solr/core/src/test/org/apache/solr/cloud/
solr/solrj/src/java/org/apache/solr/client/solrj/impl/
Author: anshum
Date: Fri May 22 06:26:10 2015
New Revision: 1681001
URL: http://svn.apache.org/r1681001
Log:
SOLR-7468: Kerberos plugin for authentication framework. This will enable using Kerberos for authentication in Solr.
Added:
lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosFilter.java (with props)
lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberos.java (with props)
lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientConfigurer.java (with props)
Modified:
lucene/dev/trunk/lucene/tools/junit4/solr-tests.policy
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/KerberosTestUtil.java
Modified: lucene/dev/trunk/lucene/tools/junit4/solr-tests.policy
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/tools/junit4/solr-tests.policy?rev=1681001&r1=1681000&r2=1681001&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/tools/junit4/solr-tests.policy (original)
+++ lucene/dev/trunk/lucene/tools/junit4/solr-tests.policy Fri May 22 06:26:10 2015
@@ -88,4 +88,7 @@ grant {
permission javax.security.auth.kerberos.ServicePermission "krbtgt/EXAMPLE.COM@EXAMPLE.COM", "initiate";
permission javax.security.auth.kerberos.ServicePermission "zookeeper/127.0.0.1@EXAMPLE.COM", "initiate";
permission javax.security.auth.kerberos.ServicePermission "zookeeper/127.0.0.1@EXAMPLE.COM", "accept";
+ permission javax.security.auth.kerberos.ServicePermission "HTTP/127.0.0.1@EXAMPLE.COM", "initiate";
+ permission javax.security.auth.kerberos.ServicePermission "HTTP/127.0.0.1@EXAMPLE.COM", "accept";
+
};
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1681001&r1=1681000&r2=1681001&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Fri May 22 06:26:10 2015
@@ -219,6 +219,9 @@ New Features
* SOLR-7465: New file indexing example, under example/files. (Esther Quansah, Erik Hatcher)
+* SOLR-7468: Kerberos authenticaion plugin for Solr. This would allow running a Kerberized Solr.
+ (Noble Paul, Ishan Chattopadhyaya, Gregory Chanan, Anshum Gupta)
+
Bug Fixes
----------------------
Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosFilter.java?rev=1681001&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosFilter.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosFilter.java Fri May 22 06:26:10 2015
@@ -0,0 +1,52 @@
+package org.apache.solr.security;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * 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.
+ */
+
+public class KerberosFilter extends AuthenticationFilter {
+
+ static final Logger log = LoggerFactory.getLogger(KerberosFilter.class);
+
+ @Override
+ public void init(FilterConfig conf) throws ServletException {
+ super.init(conf);
+ }
+
+ @Override
+ protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ super.doFilter(filterChain, request, response);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+ super.doFilter(request, response, filterChain);
+ }
+}
Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java?rev=1681001&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java Fri May 22 06:26:10 2015
@@ -0,0 +1,359 @@
+package org.apache.solr.security;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.FilterRegistration.Dynamic;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+import org.apache.commons.collections.iterators.IteratorEnumeration;
+import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
+import org.apache.solr.client.solrj.impl.Krb5HttpClientConfigurer;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * 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.
+ */
+
+public class KerberosPlugin extends AuthenticationPlugin {
+ static final Logger log = LoggerFactory.getLogger(KerberosPlugin.class);
+
+ HttpClientConfigurer kerberosConfigurer = new Krb5HttpClientConfigurer();
+ Filter kerberosFilter = new KerberosFilter();
+
+ @Override
+ public void init(Map<String, Object> pluginConfig) {
+ try {
+ Map<String, String> params = new HashMap();
+ params.put("type", "kerberos");
+ params.put("kerberos.name.rules", System.getProperty("solr.kerberos.name.rules", "DEFAULT"));
+ params.put("token.valid", System.getProperty("solr.kerberos.token.valid", "30"));
+ params.put("cookie.domain", System.getProperty("solr.kerberos.cookie.domain"));
+ params.put("cookie.path", System.getProperty("solr.kerberos.cookie.path", "/"));
+ params.put("kerberos.principal", System.getProperty("solr.kerberos.principal"));
+ params.put("kerberos.keytab", System.getProperty("solr.kerberos.keytab"));
+
+ log.info("Params: "+params);
+
+ FilterConfig conf = new FilterConfig() {
+ @Override
+ public ServletContext getServletContext() {
+ return noContext;
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return new IteratorEnumeration(params.keySet().iterator());
+ }
+
+ @Override
+ public String getInitParameter(String param) {
+ return params.get(param);
+ }
+
+ @Override
+ public String getFilterName() {
+ return "KerberosFilter";
+ }
+ };
+
+ kerberosFilter.init(conf);
+ } catch (ServletException e) {
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Error initializing kerberos authentication plugin: "+e);
+ }
+ }
+
+ @Override
+ public void doAuthenticate(ServletRequest req, ServletResponse rsp,
+ FilterChain chain) throws Exception {
+ log.debug("Request to authenticate using kerberos: "+req);
+ kerberosFilter.doFilter(req, rsp, chain);
+ }
+
+ @Override
+ public HttpClientConfigurer getDefaultConfigurer() {
+ return kerberosConfigurer;
+ }
+
+ public void close() {
+ kerberosFilter.destroy();
+ }
+
+ protected static ServletContext noContext = new ServletContext() {
+
+ @Override
+ public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {}
+
+ @Override
+ public boolean setInitParameter(String name, String value) {
+ return false;
+ }
+
+ @Override
+ public void setAttribute(String name, Object object) {}
+
+ @Override
+ public void removeAttribute(String name) {}
+
+ @Override
+ public void log(String message, Throwable throwable) {}
+
+ @Override
+ public void log(Exception exception, String msg) {}
+
+ @Override
+ public void log(String msg) {}
+
+ @Override
+ public String getVirtualServerName() {
+ return null;
+ }
+
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<Servlet> getServlets() {
+ return null;
+ }
+
+ @Override
+ public Map<String,? extends ServletRegistration> getServletRegistrations() {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration getServletRegistration(String servletName) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getServletNames() {
+ return null;
+ }
+
+ @Override
+ public String getServletContextName() {
+ return null;
+ }
+
+ @Override
+ public Servlet getServlet(String name) throws ServletException {
+ return null;
+ }
+
+ @Override
+ public String getServerInfo() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getResourcePaths(String path) {
+ return null;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String path) {
+ return null;
+ }
+
+ @Override
+ public URL getResource(String path) throws MalformedURLException {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getNamedDispatcher(String name) {
+ return null;
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return 0;
+ }
+
+ @Override
+ public String getMimeType(String file) {
+ return null;
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return 0;
+ }
+
+ @Override
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Map<String,? extends FilterRegistration> getFilterRegistrations() {
+ return null;
+ }
+
+ @Override
+ public FilterRegistration getFilterRegistration(String filterName) {
+ return null;
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ return null;
+ }
+
+ @Override
+ public int getEffectiveMinorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int getEffectiveMajorVersion() {
+ return 0;
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public ServletContext getContext(String uripath) {
+ return null;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public void declareRoles(String... roleNames) {}
+
+ @Override
+ public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className) {
+ return null;
+ }
+
+ @Override
+ public void addListener(Class<? extends EventListener> listenerClass) {}
+
+ @Override
+ public <T extends EventListener> void addListener(T t) {}
+
+ @Override
+ public void addListener(String className) {}
+
+ @Override
+ public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
+ return null;
+ }
+
+ @Override
+ public Dynamic addFilter(String filterName, Filter filter) {
+ return null;
+ }
+
+ @Override
+ public Dynamic addFilter(String filterName, String className) {
+ return null;
+ }
+ };
+}
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/KerberosTestUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/KerberosTestUtil.java?rev=1681001&r1=1681000&r2=1681001&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/KerberosTestUtil.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/KerberosTestUtil.java Fri May 22 06:26:10 2015
@@ -46,6 +46,7 @@ public class KerberosTestUtil {
private static AppConfigurationEntry[] clientEntry;
private static AppConfigurationEntry[] serverEntry;
+ private String clientAppName = "Client", serverAppName = "Server";
/**
* Add an entry to the jaas configuration with the passed in name,
@@ -58,7 +59,7 @@ public class KerberosTestUtil {
*/
public JaasConfiguration(String clientPrincipal, File clientKeytab,
String serverPrincipal, File serverKeytab) {
- Map<String, String> clientOptions = new HashMap<String, String>();
+ Map<String, String> clientOptions = new HashMap();
clientOptions.put("principal", clientPrincipal);
clientOptions.put("keyTab", clientKeytab.getAbsolutePath());
clientOptions.put("useKeyTab", "true");
@@ -73,20 +74,36 @@ public class KerberosTestUtil {
new AppConfigurationEntry(getKrb5LoginModuleName(),
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
clientOptions)};
- Map<String, String> serverOptions = new HashMap<String, String>(clientOptions);
- serverOptions.put("principal", serverPrincipal);
- serverOptions.put("keytab", serverKeytab.getAbsolutePath());
- serverEntry = new AppConfigurationEntry[]{
- new AppConfigurationEntry(getKrb5LoginModuleName(),
- AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
- serverOptions)};
+ if(serverPrincipal!=null && serverKeytab!=null) {
+ Map<String, String> serverOptions = new HashMap(clientOptions);
+ serverOptions.put("principal", serverPrincipal);
+ serverOptions.put("keytab", serverKeytab.getAbsolutePath());
+ serverEntry = new AppConfigurationEntry[]{
+ new AppConfigurationEntry(getKrb5LoginModuleName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ serverOptions)};
+ }
+ }
+
+ /**
+ * Add an entry to the jaas configuration with the passed in principal and keytab,
+ * along with the app name.
+ *
+ * @param principal The principal
+ * @param keytab The keytab containing credentials for the principal
+ * @param appName The app name of the configuration
+ */
+ public JaasConfiguration(String principal, File keytab, String appName) {
+ this(principal, keytab, null, null);
+ clientAppName = appName;
+ serverAppName = null;
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- if ("Client".equals(name)) {
+ if (name.equals(clientAppName)) {
return clientEntry;
- } else if ("Server".equals(name)) {
+ } else if (name.equals(serverAppName)) {
return serverEntry;
}
return null;
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java?rev=1681001&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java Fri May 22 06:26:10 2015
@@ -0,0 +1,176 @@
+package org.apache.solr.cloud;
+
+/*
+ * 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.
+ */
+
+import javax.security.auth.login.Configuration;
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
+import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks;
+import org.apache.solr.util.BadZookeeperThreadsFilter;
+import org.apache.solr.util.RevertDefaultThreadHandlerRule;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+
+/**
+ * Test 5 nodes Solr cluster with Kerberos plugin enabled.
+ * This test is Ignored right now as Mini KDC has a known bug that
+ * doesn't allow us to run multiple nodes on the same host.
+ * https://issues.apache.org/jira/browse/HADOOP-9893
+ */
+@ThreadLeakFilters(defaultFilters = true, filters = {
+ BadZookeeperThreadsFilter.class // Zookeeper login leaks TGT renewal threads
+})
+
+@Ignore
+@LuceneTestCase.Slow
+@SuppressSysoutChecks(bugUrl = "Solr logs to JUL")
+public class TestMiniSolrCloudClusterKerberos extends TestMiniSolrCloudCluster {
+
+ private final Configuration originalConfig = Configuration.getConfiguration();
+
+ public TestMiniSolrCloudClusterKerberos () {
+ NUM_SERVERS = 5;
+ NUM_SHARDS = 2;
+ REPLICATION_FACTOR = 2;
+ }
+
+ protected final static List<String> brokenLocales =
+ Arrays.asList(
+ "th_TH_TH_#u-nu-thai",
+ "ja_JP_JP_#u-ca-japanese",
+ "hi_IN");
+
+ private MiniKdc kdc;
+
+ @Rule
+ public TestRule solrTestRules = RuleChain
+ .outerRule(new SystemPropertiesRestoreRule());
+
+ @ClassRule
+ public static TestRule solrClassRules = RuleChain.outerRule(
+ new SystemPropertiesRestoreRule()).around(
+ new RevertDefaultThreadHandlerRule());
+
+ @Override
+ public void setUp() throws Exception {
+ if (brokenLocales.contains(Locale.getDefault().toString())) {
+ Locale.setDefault(Locale.US);
+ }
+ super.setUp();
+ setupMiniKdc();
+ }
+
+ private void setupMiniKdc() throws Exception {
+ String kdcDir = createTempDir()+File.separator+"minikdc";
+ kdc = KerberosTestUtil.getKdc(new File(kdcDir));
+ File keytabFile = new File(kdcDir, "keytabs");
+ String principal = "HTTP/127.0.0.1";
+ String zkServerPrincipal = "zookeeper/127.0.0.1";
+
+ kdc.start();
+ kdc.createPrincipal(keytabFile, principal, zkServerPrincipal);
+
+ String jaas = "Client {\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=\""+principal+"\";\n"
+ + "};\n"
+ + "Server {\n"
+ + " com.sun.security.auth.module.Krb5LoginModule required\n"
+ + " useKeyTab=true\n"
+ + " keyTab=\""+keytabFile.getAbsolutePath()+"\"\n"
+ + " storeKey=true\n"
+ + " doNotPrompt=true\n"
+ + " useTicketCache=false\n"
+ + " debug=true\n"
+ + " principal=\""+zkServerPrincipal+"\";\n"
+ + "};\n";
+
+ Configuration conf = new KerberosTestUtil.JaasConfiguration(principal, keytabFile, zkServerPrincipal, keytabFile);
+ javax.security.auth.login.Configuration.setConfiguration(conf);
+
+ String jaasFilePath = kdcDir+File.separator + "jaas-client.conf";
+ FileUtils.write(new File(jaasFilePath), jaas);
+ System.setProperty("java.security.auth.login.config", jaasFilePath);
+ System.setProperty("solr.kerberos.cookie.domain", "127.0.0.1");
+ System.setProperty("solr.kerberos.principal", principal);
+ System.setProperty("solr.kerberos.keytab", keytabFile.getAbsolutePath());
+ System.setProperty("authenticationPlugin", "org.apache.solr.security.KerberosPlugin");
+
+ // more debugging, if needed
+ /*System.setProperty("sun.security.jgss.debug", "true");
+ System.setProperty("sun.security.krb5.debug", "true");
+ System.setProperty("sun.security.jgss.debug", "true");
+ System.setProperty("java.security.debug", "logincontext,policy,scl,gssloginconfig");*/
+ }
+
+ @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")
+ @Test
+ @Override
+ public void testBasics() throws Exception {
+ testCollectionCreateSearchDelete();
+ // sometimes run a second test e.g. to test collection create-delete-create scenario
+ if (random().nextBoolean()) testCollectionCreateSearchDelete();
+ }
+
+ @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")
+ @Test
+ @Override
+ public void testErrorsInShutdown() throws Exception {
+ super.testErrorsInShutdown();
+ }
+
+ @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")
+ @Test
+ @Override
+ public void testErrorsInStartup() throws Exception {
+ super.testErrorsInStartup();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ System.clearProperty("java.security.auth.login.config");
+ System.clearProperty("cookie.domain");
+ System.clearProperty("kerberos.principal");
+ System.clearProperty("kerberos.keytab");
+ System.clearProperty("authenticationPlugin");
+ Configuration.setConfiguration(this.originalConfig);
+ if (kdc != null) {
+ kdc.stop();
+ }
+ super.tearDown();
+ }
+}
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberos.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberos.java?rev=1681001&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberos.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberos.java Fri May 22 06:26:10 2015
@@ -0,0 +1,183 @@
+package org.apache.solr.cloud;
+
+/*
+ * 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.
+ */
+
+import javax.security.auth.login.Configuration;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.io.Charsets;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.minikdc.MiniKdc;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.response.CollectionAdminResponse;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.zookeeper.CreateMode;
+import org.junit.Test;
+
+@SolrTestCaseJ4.SuppressSSL
+@LuceneTestCase.Slow
+public class TestSolrCloudWithKerberos extends AbstractFullDistribZkTestBase {
+
+ static final int TIMEOUT = 10000;
+ private MiniKdc kdc;
+
+ protected final static List<String> brokenLocales =
+ Arrays.asList(
+ "th_TH_TH_#u-nu-thai",
+ "ja_JP_JP_#u-ca-japanese",
+ "hi_IN");
+
+ Configuration originalConfig = Configuration.getConfiguration();
+
+ @Override
+ public void distribSetUp() throws Exception {
+ //SSLTestConfig.setSSLSystemProperties();
+ if (brokenLocales.contains(Locale.getDefault().toString())) {
+ Locale.setDefault(Locale.US);
+ }
+ setupMiniKdc();
+ super.distribSetUp();
+ //useExternalKdc();
+ try (ZkStateReader zkStateReader = new ZkStateReader(zkServer.getZkAddress(), TIMEOUT, TIMEOUT)) {
+ zkStateReader.getZkClient().create(ZkStateReader.SOLR_SECURITY_CONF_PATH,
+ "{\"authentication\":{\"class\":\"org.apache.solr.security.KerberosPlugin\"}}".getBytes(Charsets.UTF_8),
+ CreateMode.PERSISTENT, true);
+ }
+ }
+
+ private void setupMiniKdc() throws Exception {
+ String kdcDir = createTempDir()+File.separator+"minikdc";
+ kdc = KerberosTestUtil.getKdc(new File(kdcDir));
+ File keytabFile = new File(kdcDir, "keytabs");
+ String solrServerPrincipal = "HTTP/127.0.0.1";
+ String zkServerPrincipal = "zookeeper/127.0.0.1";
+
+ kdc.start();
+ kdc.createPrincipal(keytabFile, solrServerPrincipal, zkServerPrincipal);
+
+ 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=\"" + solrServerPrincipal + "\";\n"
+ + "};";
+
+ Configuration conf = new KerberosTestUtil.JaasConfiguration(solrServerPrincipal, keytabFile, "SolrClient");
+ Configuration.setConfiguration(conf);
+
+ String jaasFilePath = kdcDir+File.separator+"jaas-client.conf";
+ FileUtils.write(new File(jaasFilePath), jaas);
+ 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.cookie.domain", "127.0.0.1");
+ System.setProperty("solr.kerberos.principal", solrServerPrincipal);
+ System.setProperty("solr.kerberos.keytab", keytabFile.getAbsolutePath());
+
+ // more debugging, if needed
+ /*System.setProperty("sun.security.jgss.debug", "true");
+ System.setProperty("sun.security.krb5.debug", "true");
+ System.setProperty("sun.security.jgss.debug", "true");
+ System.setProperty("java.security.debug", "logincontext,policy,scl,gssloginconfig");*/
+ }
+
+ //This method can be used for debugging i.e. to use an external KDC for the test.
+ private void useExternalKdc() throws Exception {
+
+ String jaas = "Client {\n"
+ +" com.sun.security.auth.module.Krb5LoginModule required\n"
+ +" useKeyTab=true\n"
+ +" keyTab=\"/tmp/127.keytab\"\n"
+ +" storeKey=true\n"
+ +" useTicketCache=false\n"
+ +" debug=true\n"
+ +" principal=\"HTTP/127.0.0.1\";\n"
+ +"};\n"
+ + "\n"
+ + "Server {\n"
+ +" com.sun.security.auth.module.Krb5LoginModule optional\n"
+ +" useKeyTab=true\n"
+ +" keyTab=\"/tmp/127.keytab\"\n"
+ +" storeKey=true\n"
+ +" useTicketCache=false\n"
+ +" debug=true\n"
+ +" principal=\"zookeeper/127.0.0.1\";\n"
+ +"};";
+
+ String tmpDir = createTempDir().toString();
+ FileUtils.write(new File(tmpDir + File.separator + "jaas.conf"), jaas);
+
+ System.setProperty("java.security.auth.login.config", tmpDir + File.separator + "jaas.conf");
+ System.setProperty("solr.kerberos.jaas.appname", "Client");
+ System.setProperty("solr.kerberos.cookie.domain", "127.0.0.1");
+ System.setProperty("solr.kerberos.principal", "HTTP/127.0.0.1@EXAMPLE.COM");
+ System.setProperty("solr.kerberos.keytab", "/tmp/127.keytab");
+ System.setProperty("authenticationPlugin", "org.apache.solr.security.KerberosPlugin");
+ }
+
+ @Test
+ public void testKerberizedSolr() throws Exception {
+ CollectionAdminRequest.Create create = new CollectionAdminRequest.Create();
+ create.setCollectionName("testcollection");
+ create.setConfigName("conf1");
+ create.setNumShards(1);
+ create.setReplicationFactor(1);
+ create.process(cloudClient);
+
+ waitForCollection(cloudClient.getZkStateReader(), "testcollection", 1);
+ CollectionAdminRequest.List list = new CollectionAdminRequest.List();
+
+ CollectionAdminResponse response = list.process(cloudClient);
+ assertTrue("Expected to see testcollection but it doesn't exist",
+ ((ArrayList) response.getResponse().get("collections")).contains("testcollection"));
+
+ cloudClient.setDefaultCollection("testcollection");
+ indexDoc(cloudClient, params("commit", "true"), getDoc("id", 1));
+ //cloudClient.commit();
+
+ QueryResponse queryResponse = cloudClient.query(new SolrQuery("*:*"));
+ assertEquals("Expected #docs and actual isn't the same", 1, queryResponse.getResults().size());
+ }
+
+ @Override
+ public void distribTearDown() throws Exception {
+ System.clearProperty("java.security.auth.login.config");
+ System.clearProperty("solr.kerberos.jaas.appname");
+ System.clearProperty("solr.cookie.domain");
+ System.clearProperty("solr.kerberos.principal");
+ System.clearProperty("solr.kerberos.keytab");
+ Configuration.setConfiguration(originalConfig);
+ if (kdc != null) {
+ kdc.stop();
+ }
+ //SSLTestConfig.clearSSLSystemProperties();
+ super.distribTearDown();
+ }
+}
Added: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientConfigurer.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientConfigurer.java?rev=1681001&view=auto
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientConfigurer.java (added)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Krb5HttpClientConfigurer.java Fri May 22 06:26:10 2015
@@ -0,0 +1,144 @@
+package org.apache.solr.client.solrj.impl;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.impl.auth.SPNegoSchemeFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.client.config.AuthSchemes;
+import org.apache.solr.common.params.SolrParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.http.entity.BufferedHttpEntity;
+
+/**
+ * Kerberos-enabled HttpClientConfigurer
+ */
+public class Krb5HttpClientConfigurer extends HttpClientConfigurer {
+
+ public static final String LOGIN_CONFIG_PROP = "java.security.auth.login.config";
+ private static final Logger logger = LoggerFactory.getLogger(Krb5HttpClientConfigurer.class);
+
+ private static final Configuration jaasConfig = new SolrJaasConfiguration();
+
+ public void configure(DefaultHttpClient httpClient, SolrParams config) {
+ super.configure(httpClient, config);
+
+ if (System.getProperty(LOGIN_CONFIG_PROP) != null) {
+ String configValue = System.getProperty(LOGIN_CONFIG_PROP);
+
+ if (configValue != null) {
+ logger.info("Setting up SPNego auth with config: " + configValue);
+ final String useSubjectCredsProp = "javax.security.auth.useSubjectCredsOnly";
+ String useSubjectCredsVal = System.getProperty(useSubjectCredsProp);
+
+ // "javax.security.auth.useSubjectCredsOnly" should be false so that the underlying
+ // authentication mechanism can load the credentials from the JAAS configuration.
+ if (useSubjectCredsVal == null) {
+ System.setProperty(useSubjectCredsProp, "false");
+ }
+ else if (!useSubjectCredsVal.toLowerCase(Locale.ROOT).equals("false")) {
+ // Don't overwrite the prop value if it's already been written to something else,
+ // but log because it is likely the Credentials won't be loaded correctly.
+ logger.warn("System Property: " + useSubjectCredsProp + " set to: " + useSubjectCredsVal
+ + " not false. SPNego authentication may not be successful.");
+ }
+
+ javax.security.auth.login.Configuration.setConfiguration(jaasConfig);
+ httpClient.getAuthSchemes().register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true, false));
+ // Get the credentials from the JAAS configuration rather than here
+ Credentials useJaasCreds = new Credentials() {
+ public String getPassword() {
+ return null;
+ }
+ public Principal getUserPrincipal() {
+ return null;
+ }
+ };
+
+ httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, useJaasCreds);
+
+ httpClient.addRequestInterceptor(bufferedEntityInterceptor);
+ } else {
+ httpClient.getCredentialsProvider().clear();
+ }
+ }
+ }
+
+ // Set a buffered entity based request interceptor
+ private HttpRequestInterceptor bufferedEntityInterceptor = new HttpRequestInterceptor() {
+ @Override
+ public void process(HttpRequest request, HttpContext context) throws HttpException,
+ IOException {
+ if(request instanceof HttpEntityEnclosingRequest) {
+ HttpEntityEnclosingRequest enclosingRequest = ((HttpEntityEnclosingRequest) request);
+ HttpEntity requestEntity = enclosingRequest.getEntity();
+ enclosingRequest.setEntity(new BufferedHttpEntity(requestEntity));
+ }
+ }
+ };
+
+ private static class SolrJaasConfiguration extends javax.security.auth.login.Configuration {
+
+ private javax.security.auth.login.Configuration baseConfig;
+
+ // the com.sun.security.jgss appNames
+ private Set<String> initiateAppNames = new HashSet(
+ Arrays.asList("com.sun.security.jgss.krb5.initiate", "com.sun.security.jgss.initiate"));
+
+ public SolrJaasConfiguration() {
+ try {
+
+ this.baseConfig = javax.security.auth.login.Configuration.getConfiguration();
+ } catch (SecurityException e) {
+ this.baseConfig = null;
+ }
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
+ if (baseConfig == null) return null;
+
+ logger.debug("Login prop: "+System.getProperty(LOGIN_CONFIG_PROP));
+
+ String clientAppName = System.getProperty("solr.kerberos.jaas.appname", "Client");
+ if (initiateAppNames.contains(appName)) {
+ logger.debug("Using AppConfigurationEntry for appName '"+clientAppName+"' instead of: " + appName);
+ return baseConfig.getAppConfigurationEntry(clientAppName);
+ }
+ return baseConfig.getAppConfigurationEntry(appName);
+ }
+ }
+}