You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by yo...@apache.org on 2016/11/17 21:39:45 UTC

[1/5] lucene-solr:branch_6x: SOLR-9460: Fully fix test setup

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6x 722e77a69 -> f084e658b


SOLR-9460: Fully fix test setup


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/6428772a
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/6428772a
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/6428772a

Branch: refs/heads/branch_6x
Commit: 6428772aa2cd3a1c344cfcaeec7c30fd46071134
Parents: 225198a
Author: Uwe Schindler <us...@apache.org>
Authored: Sat Sep 3 20:30:30 2016 +0200
Committer: yonik <yo...@apache.org>
Committed: Thu Nov 17 15:05:46 2016 -0500

----------------------------------------------------------------------
 .../TestSolrCloudWithSecureImpersonation.java   | 22 ++++++++++++--------
 1 file changed, 13 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6428772a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
index 3727620..ef41e4d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
@@ -58,16 +58,18 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
   private static SolrClient solrClient;
 
   private static String getUsersFirstGroup() throws Exception {
-    org.apache.hadoop.security.Groups hGroups =
-        new org.apache.hadoop.security.Groups(new Configuration());
     String group = "*"; // accept any group if a group can't be found
-    try {
-      List<String> g = hGroups.getGroups(System.getProperty("user.name"));
-      if (g != null && g.size() > 0) {
-        group = g.get(0);
+    if (!Constants.WINDOWS) { // does not work on Windows!
+      org.apache.hadoop.security.Groups hGroups =
+          new org.apache.hadoop.security.Groups(new Configuration());
+      try {
+        List<String> g = hGroups.getGroups(System.getProperty("user.name"));
+        if (g != null && g.size() > 0) {
+          group = g.get(0);
+        }
+      } catch (NullPointerException npe) {
+        // if user/group doesn't exist on test box
       }
-    } catch (NullPointerException npe) {
-      // if user/group doesn't exist on test box
     }
     return group;
   }
@@ -154,7 +156,9 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
       miniCluster.shutdown();
     }
     miniCluster = null;
-    solrClient.close();
+    if (solrClient != null) {
+      solrClient.close();
+    }
     solrClient = null;
     System.clearProperty("authenticationPlugin");
     System.clearProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED);


[4/5] lucene-solr:branch_6x: SOLR-9324: Fix local host test assumptions

Posted by yo...@apache.org.
SOLR-9324: Fix local host test assumptions


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/8659fe1c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/8659fe1c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/8659fe1c

Branch: refs/heads/branch_6x
Commit: 8659fe1cce3f49f37f50f9a74d0eb79ad8d1bf58
Parents: f78f698
Author: Gregory Chanan <gc...@cloudera.com>
Authored: Sat Aug 6 00:04:58 2016 -0400
Committer: yonik <yo...@apache.org>
Committed: Thu Nov 17 15:05:46 2016 -0500

----------------------------------------------------------------------
 .../TestSolrCloudWithSecureImpersonation.java   | 23 +++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8659fe1c/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
index 1839d32..71107ee 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
@@ -18,6 +18,7 @@ package org.apache.solr.cloud;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.File;
+import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -42,6 +43,7 @@ import org.apache.solr.security.HttpParamDelegationTokenPlugin;
 import org.apache.solr.security.KerberosPlugin;
 import org.apache.solr.servlet.SolrRequestParsers;
 import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -57,8 +59,16 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
   private static String getUsersFirstGroup() throws Exception {
     org.apache.hadoop.security.Groups hGroups =
         new org.apache.hadoop.security.Groups(new Configuration());
-    List<String> g = hGroups.getGroups(System.getProperty("user.name"));
-    return g.get(0);
+    String group = "*"; // accept any group if a group can't be found
+    try {
+      List<String> g = hGroups.getGroups(System.getProperty("user.name"));
+      if (g != null && g.size() > 0) {
+        group = g.get(0);
+      }
+    } catch (NullPointerException npe) {
+      // if user/group doesn't exist on test box
+    }
+    return group;
   }
 
   private static Map<String, String> getImpersonatorSettings() throws Exception {
@@ -70,7 +80,9 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "wrongHost.groups", "*");
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "noHosts.groups", "*");
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "localHostAnyGroup.groups", "*");
-    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "localHostAnyGroup.hosts", "127.0.0.1");
+    InetAddress loopback = InetAddress.getLoopbackAddress();
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "localHostAnyGroup.hosts",
+        loopback.getCanonicalHostName() + "," + loopback.getHostName() + "," + loopback.getHostAddress());
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostUsersGroup.groups", getUsersFirstGroup());
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostUsersGroup.hosts", "*");
     filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "bogusGroup.groups", "__some_bogus_group");
@@ -128,6 +140,11 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
     }
   }
 
+  @Before
+  public void clearCalledIndicator() throws Exception {
+    ImpersonatorCollectionsHandler.called.set(false);
+  }
+
   @AfterClass
   public static void shutdown() throws Exception {
     if (miniCluster != null) {


[3/5] lucene-solr:branch_6x: SOLR-9324: Support Secure Impersonation / Proxy User for solr authentication

Posted by yo...@apache.org.
SOLR-9324: Support Secure Impersonation / Proxy User for solr authentication

Conflicts:
	solr/CHANGES.txt
	solr/core/src/java/org/apache/solr/security/KerberosPlugin.java


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f78f698a
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f78f698a
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f78f698a

Branch: refs/heads/branch_6x
Commit: f78f698ab0a919e4923f0cbf061dfa254e177555
Parents: 722e77a
Author: Gregory Chanan <gc...@cloudera.com>
Authored: Mon Jul 25 14:15:48 2016 -0400
Committer: yonik <yo...@apache.org>
Committed: Thu Nov 17 15:05:46 2016 -0500

----------------------------------------------------------------------
 .../security/DelegationTokenKerberosFilter.java |  46 ++-
 .../apache/solr/security/KerberosPlugin.java    | 205 ++++++-----
 .../TestSolrCloudWithDelegationTokens.java      |   9 +-
 .../TestSolrCloudWithSecureImpersonation.java   | 340 +++++++++++++++++++
 ...ramDelegationTokenAuthenticationHandler.java | 109 ------
 .../HttpParamDelegationTokenPlugin.java         | 272 +++++++++++++++
 6 files changed, 776 insertions(+), 205 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f78f698a/solr/core/src/java/org/apache/solr/security/DelegationTokenKerberosFilter.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/security/DelegationTokenKerberosFilter.java b/solr/core/src/java/org/apache/solr/security/DelegationTokenKerberosFilter.java
index a96605d..421de52 100644
--- a/solr/core/src/java/org/apache/solr/security/DelegationTokenKerberosFilter.java
+++ b/solr/core/src/java/org/apache/solr/security/DelegationTokenKerberosFilter.java
@@ -18,6 +18,7 @@ package org.apache.solr.security;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.util.Enumeration;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -36,8 +37,11 @@ import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.api.ACLProvider;
 import org.apache.curator.retry.ExponentialBackoffRetry;
 
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
 import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationFilter;
+import org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
 import org.apache.solr.common.cloud.SecurityAwareZkACLProvider;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkACLProvider;
@@ -67,6 +71,27 @@ public class DelegationTokenKerberosFilter extends DelegationTokenAuthentication
     super.init(conf);
   }
 
+  /**
+   * Return the ProxyUser Configuration.  FilterConfig properties beginning with
+   * "solr.impersonator.user.name" will be added to the configuration.
+   */
+  @Override
+  protected Configuration getProxyuserConfiguration(FilterConfig filterConf)
+      throws ServletException {
+    Configuration conf = new Configuration(false);
+
+    Enumeration<?> names = filterConf.getInitParameterNames();
+    while (names.hasMoreElements()) {
+      String name = (String) names.nextElement();
+      if (name.startsWith(KerberosPlugin.IMPERSONATOR_PREFIX)) {
+        String value = filterConf.getInitParameter(name);
+        conf.set(PROXYUSER_PREFIX + "." + name.substring(KerberosPlugin.IMPERSONATOR_PREFIX.length()), value);
+        conf.set(name, value);
+      }
+    }
+    return conf;
+  }
+
   @Override
   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain filterChain) throws IOException, ServletException {
@@ -81,7 +106,26 @@ public class DelegationTokenKerberosFilter extends DelegationTokenAuthentication
         return nonNullQueryString;
       }
     };
-    super.doFilter(requestNonNullQueryString, response, filterChain);
+
+    // include Impersonator User Name in case someone (e.g. logger) wants it
+    FilterChain filterChainWrapper = new FilterChain() {
+      @Override
+      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
+          throws IOException, ServletException {
+        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+
+        UserGroupInformation ugi = HttpUserGroupInformation.get();
+        if (ugi != null && ugi.getAuthenticationMethod() == UserGroupInformation.AuthenticationMethod.PROXY) {
+          UserGroupInformation realUserUgi = ugi.getRealUser();
+          if (realUserUgi != null) {
+            httpRequest.setAttribute(KerberosPlugin.IMPERSONATOR_USER_NAME, realUserUgi.getShortUserName());
+          }
+        }
+        filterChain.doFilter(servletRequest, servletResponse);
+      }
+    };
+
+    super.doFilter(requestNonNullQueryString, response, filterChainWrapper);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f78f698a/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java b/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
index 0eac9ae..b04ea49 100644
--- a/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
@@ -53,17 +53,21 @@ import org.apache.commons.collections.iterators.IteratorEnumeration;
 import org.apache.hadoop.security.authentication.client.AuthenticationException;
 import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
 import org.apache.hadoop.security.authentication.server.AuthenticationToken;
+import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
 import org.apache.solr.client.solrj.impl.Krb5HttpClientConfigurer;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.SecurityAwareZkACLProvider;
+import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.SuppressForbidden;
 import org.apache.solr.core.CoreContainer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
+
 public class KerberosPlugin extends AuthenticationPlugin implements HttpClientInterceptorPlugin {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -77,6 +81,7 @@ public class KerberosPlugin extends AuthenticationPlugin implements HttpClientIn
   public static final String KEYTAB_PARAM = "solr.kerberos.keytab";
   public static final String TOKEN_VALID_PARAM = "solr.kerberos.token.valid";
   public static final String COOKIE_PORT_AWARE_PARAM = "solr.kerberos.cookie.portaware";
+  public static final String IMPERSONATOR_PREFIX = "solr.kerberos.impersonator.user.";
   public static final String DELEGATION_TOKEN_ENABLED = "solr.kerberos.delegation.token.enabled";
   public static final String DELEGATION_TOKEN_KIND = "solr.kerberos.delegation.token.kind";
   public static final String DELEGATION_TOKEN_VALIDITY = "solr.kerberos.delegation.token.validity";
@@ -85,8 +90,11 @@ public class KerberosPlugin extends AuthenticationPlugin implements HttpClientIn
       "solr.kerberos.delegation.token.signer.secret.provider.zookeper.path";
   public static final String DELEGATION_TOKEN_SECRET_MANAGER_ZNODE_WORKING_PATH =
       "solr.kerberos.delegation.token.secret.manager.znode.working.path";
+
   public static final String DELEGATION_TOKEN_TYPE_DEFAULT = "solr-dt";
-  
+  public static final String IMPERSONATOR_DO_AS_HTTP_PARAM = "doAs";
+  public static final String IMPERSONATOR_USER_NAME = "solr.impersonator.user.name";
+
   // filled in by Plugin/Filter
   static final String REQUEST_CONTINUES_ATTR =
       "org.apache.solr.security.kerberosplugin.requestcontinues";
@@ -105,107 +113,121 @@ public class KerberosPlugin extends AuthenticationPlugin implements HttpClientIn
   @Override
   public void init(Map<String, Object> pluginConfig) {
     try {
-      Map<String, String> params = new HashMap();
-      putParam(params, "type", AUTH_HANDLER_PARAM, "kerberos");
-      putParam(params, "kerberos.name.rules", NAME_RULES_PARAM, "DEFAULT");
-      putParam(params, "token.valid", TOKEN_VALID_PARAM, "30");
-      putParam(params, "cookie.path", COOKIE_PATH_PARAM, "/");
-      if ("kerberos".equals(params.get("type"))) {
-        putParam(params, "kerberos.principal", PRINCIPAL_PARAM, null);
-        putParam(params, "kerberos.keytab", KEYTAB_PARAM, null);
-      } else {
-        // allow tests which specify AUTH_HANDLER_PARAM to avoid specifying kerberos principal/keytab
-        putParamOptional(params, "kerberos.principal", PRINCIPAL_PARAM);
-        putParamOptional(params, "kerberos.keytab", KEYTAB_PARAM);
-      }
+      FilterConfig conf = getInitFilterConfig(pluginConfig, false);
+      kerberosFilter.init(conf);
+    } catch (ServletException e) {
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Error initializing kerberos authentication plugin: "+e);
+    }
+  }
 
-      String delegationTokenStr = System.getProperty(DELEGATION_TOKEN_ENABLED, null);
-      boolean delegationTokenEnabled =
-          (delegationTokenStr == null) ? false : Boolean.parseBoolean(delegationTokenStr);
-      ZkController controller = coreContainer.getZkController();
-
-      if (delegationTokenEnabled) {
-        putParam(params, "delegation-token.token-kind", DELEGATION_TOKEN_KIND, DELEGATION_TOKEN_TYPE_DEFAULT);
-        if (coreContainer.isZooKeeperAware()) {
-          putParam(params, "signer.secret.provider", DELEGATION_TOKEN_SECRET_PROVIDER, "zookeeper");
-          if ("zookeeper".equals(params.get("signer.secret.provider"))) {
-            String zkHost = controller.getZkServerAddress();
-            putParam(params, "token.validity", DELEGATION_TOKEN_VALIDITY, "36000");
-            params.put("zk-dt-secret-manager.enable", "true");
-
-            String chrootPath = zkHost.contains("/")? zkHost.substring(zkHost.indexOf("/")): "";
-            String znodeWorkingPath = chrootPath + SecurityAwareZkACLProvider.SECURITY_ZNODE_PATH + "/zkdtsm";
-            // Note - Curator complains if the znodeWorkingPath starts with /
-            znodeWorkingPath = znodeWorkingPath.startsWith("/")? znodeWorkingPath.substring(1): znodeWorkingPath;
-            putParam(params, "zk-dt-secret-manager.znodeWorkingPath",
-                DELEGATION_TOKEN_SECRET_MANAGER_ZNODE_WORKING_PATH, znodeWorkingPath);
-            putParam(params, "signer.secret.provider.zookeeper.path",
-                DELEGATION_TOKEN_SECRET_PROVIDER_ZK_PATH, "/token");
-            // need to ensure krb5 is setup properly before running curator;
-            // the coreContainer should take care of this by calling configure on the
-            // kerberosConfigurer.
-          }
-        } else {
-          log.info("CoreContainer is not ZooKeeperAware, not setting ZK-related delegation token properties");
+  @VisibleForTesting
+  protected FilterConfig getInitFilterConfig(Map<String, Object> pluginConfig, boolean skipKerberosChecking) {
+    Map<String, String> params = new HashMap();
+    params.put("type", "kerberos");
+    putParam(params, "kerberos.name.rules", NAME_RULES_PARAM, "DEFAULT");
+    putParam(params, "token.valid", TOKEN_VALID_PARAM, "30");
+    putParam(params, "cookie.path", COOKIE_PATH_PARAM, "/");
+    if (!skipKerberosChecking) {
+      putParam(params, "kerberos.principal", PRINCIPAL_PARAM, null);
+      putParam(params, "kerberos.keytab", KEYTAB_PARAM, null);
+    } else {
+      putParamOptional(params, "kerberos.principal", PRINCIPAL_PARAM);
+      putParamOptional(params, "kerberos.keytab", KEYTAB_PARAM);
+    }
+
+    String delegationTokenStr = System.getProperty(DELEGATION_TOKEN_ENABLED, null);
+    boolean delegationTokenEnabled =
+        (delegationTokenStr == null) ? false : Boolean.parseBoolean(delegationTokenStr);
+    ZkController controller = coreContainer.getZkController();
+
+    if (delegationTokenEnabled) {
+      putParam(params, "delegation-token.token-kind", DELEGATION_TOKEN_KIND, DELEGATION_TOKEN_TYPE_DEFAULT);
+      if (coreContainer.isZooKeeperAware()) {
+        putParam(params, "signer.secret.provider", DELEGATION_TOKEN_SECRET_PROVIDER, "zookeeper");
+        if ("zookeeper".equals(params.get("signer.secret.provider"))) {
+          String zkHost = controller.getZkServerAddress();
+          putParam(params, "token.validity", DELEGATION_TOKEN_VALIDITY, "36000");
+          params.put("zk-dt-secret-manager.enable", "true");
+          // Note - Curator complains if the znodeWorkingPath starts with /
+          String chrootPath = zkHost.substring(zkHost.indexOf("/"));
+          String relativePath = chrootPath.startsWith("/") ? chrootPath.substring(1) : chrootPath;
+          putParam(params, "zk-dt-secret-manager.znodeWorkingPath",
+              DELEGATION_TOKEN_SECRET_MANAGER_ZNODE_WORKING_PATH,
+              relativePath + SecurityAwareZkACLProvider.SECURITY_ZNODE_PATH + "/zkdtsm");
+          putParam(params, "signer.secret.provider.zookeeper.path",
+              DELEGATION_TOKEN_SECRET_PROVIDER_ZK_PATH, "/token");
+          // ensure krb5 is setup properly before running curator
+          kerberosConfigurer.configure(new DefaultHttpClient(), new ModifiableSolrParams());
         }
+      } else {
+        log.info("CoreContainer is not ZooKeeperAware, not setting ZK-related delegation token properties");
       }
+    }
 
-      // Special handling for the "cookie.domain" based on whether port should be
-      // appended to the domain. Useful for situations where multiple solr nodes are
-      // on the same host.
-      String usePortStr = System.getProperty(COOKIE_PORT_AWARE_PARAM, null);
-      boolean needPortAwareCookies = (usePortStr == null) ? false: Boolean.parseBoolean(usePortStr);
-
-      if (!needPortAwareCookies || !coreContainer.isZooKeeperAware()) {
-        putParam(params, "cookie.domain", COOKIE_DOMAIN_PARAM, null);
-      } else { // we need port aware cookies and we are in SolrCloud mode.
-        String host = System.getProperty(COOKIE_DOMAIN_PARAM, null);
-        if (host==null) {
-          throw new SolrException(ErrorCode.SERVER_ERROR, "Missing required parameter '"+COOKIE_DOMAIN_PARAM+"'.");
-        }
-        int port = controller.getHostPort();
-        params.put("cookie.domain", host + ":" + port);
+    // Special handling for the "cookie.domain" based on whether port should be
+    // appended to the domain. Useful for situations where multiple solr nodes are
+    // on the same host.
+    String usePortStr = System.getProperty(COOKIE_PORT_AWARE_PARAM, null);
+    boolean needPortAwareCookies = (usePortStr == null) ? false: Boolean.parseBoolean(usePortStr);
+
+    if (!needPortAwareCookies || !coreContainer.isZooKeeperAware()) {
+      putParam(params, "cookie.domain", COOKIE_DOMAIN_PARAM, null);
+    } else { // we need port aware cookies and we are in SolrCloud mode.
+      String host = System.getProperty(COOKIE_DOMAIN_PARAM, null);
+      if (host==null) {
+        throw new SolrException(ErrorCode.SERVER_ERROR, "Missing required parameter '"+COOKIE_DOMAIN_PARAM+"'.");
       }
+      int port = controller.getHostPort();
+      params.put("cookie.domain", host + ":" + port);
+    }
 
-      final ServletContext servletContext = new AttributeOnlyServletContext();
-      if (delegationTokenEnabled) {
-        kerberosFilter = new DelegationTokenKerberosFilter();
-        // pass an attribute-enabled context in order to pass the zkClient
-        // and because the filter may pass a curator instance.
-        if (controller != null) {
-          servletContext.setAttribute(DELEGATION_TOKEN_ZK_CLIENT, controller.getZkClient());
+    // check impersonator config
+    for (Enumeration e = System.getProperties().propertyNames(); e.hasMoreElements();) {
+      String key = e.nextElement().toString();
+      if (key.startsWith(IMPERSONATOR_PREFIX)) {
+        if (!delegationTokenEnabled) {
+          throw new SolrException(ErrorCode.SERVER_ERROR,
+              "Impersonator configuration requires delegation tokens to be enabled: " + key);
         }
-      } else {
-        kerberosFilter = new KerberosFilter();
+        params.put(key, System.getProperty(key));
       }
-      log.info("Params: "+params);
+    }
+    final ServletContext servletContext = new AttributeOnlyServletContext();
+    if (controller != null) {
+      servletContext.setAttribute(DELEGATION_TOKEN_ZK_CLIENT, controller.getZkClient());
+    }
+    if (delegationTokenEnabled) {
+      kerberosFilter = new DelegationTokenKerberosFilter();
+      // pass an attribute-enabled context in order to pass the zkClient
+      // and because the filter may pass a curator instance.
+    } else {
+      kerberosFilter = new KerberosFilter();
+    }
+    log.info("Params: "+params);
 
-      FilterConfig conf = new FilterConfig() {
-        @Override
-        public ServletContext getServletContext() {
-          return servletContext;
-        }
+    FilterConfig conf = new FilterConfig() {
+      @Override
+      public ServletContext getServletContext() {
+        return servletContext;
+      }
 
-        @Override
-        public Enumeration<String> getInitParameterNames() {
-          return new IteratorEnumeration(params.keySet().iterator());
-        }
+      @Override
+      public Enumeration<String> getInitParameterNames() {
+        return new IteratorEnumeration(params.keySet().iterator());
+      }
 
-        @Override
-        public String getInitParameter(String param) {
-          return params.get(param);
-        }
+      @Override
+      public String getInitParameter(String param) {
+        return params.get(param);
+      }
 
-        @Override
-        public String getFilterName() {
-          return "KerberosFilter";
-        }
-      };
+      @Override
+      public String getFilterName() {
+        return "KerberosFilter";
+      }
+    };
 
-      kerberosFilter.init(conf);
-    } catch (ServletException e) {
-      throw new SolrException(ErrorCode.SERVER_ERROR, "Error initializing kerberos authentication plugin: "+e);
-    }
+    return conf;
   }
 
   private void putParam(Map<String, String> params, String internalParamName, String externalParamName, String defaultValue) {
@@ -260,10 +282,15 @@ public class KerberosPlugin extends AuthenticationPlugin implements HttpClientIn
     return kerberosConfigurer;
   }
 
+  @Override
   public void close() {
     kerberosFilter.destroy();
   }
 
+  protected Filter getKerberosFilter() { return kerberosFilter; }
+
+  protected void setKerberosFilter(Filter kerberosFilter) { this.kerberosFilter = kerberosFilter; }
+
   protected static class AttributeOnlyServletContext implements ServletContext {
     private Map<String, Object> attributes = new HashMap<String, Object>();
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f78f698a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
index 364f004..053cea8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
@@ -33,10 +33,10 @@ import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
-import static org.apache.solr.security.HttpParamDelegationTokenAuthenticationHandler.USER_PARAM;
+import static org.apache.solr.security.HttpParamDelegationTokenPlugin.USER_PARAM;
 
 import org.apache.http.HttpStatus;
-import org.apache.solr.security.HttpParamDelegationTokenAuthenticationHandler;
+import org.apache.solr.security.HttpParamDelegationTokenPlugin;
 import org.apache.solr.security.KerberosPlugin;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -63,10 +63,8 @@ public class TestSolrCloudWithDelegationTokens extends SolrTestCaseJ4 {
 
   @BeforeClass
   public static void startup() throws Exception {
-    System.setProperty("authenticationPlugin", KerberosPlugin.class.getName());
+    System.setProperty("authenticationPlugin", HttpParamDelegationTokenPlugin.class.getName());
     System.setProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED, "true");
-    System.setProperty(KerberosPlugin.AUTH_HANDLER_PARAM,
-        HttpParamDelegationTokenAuthenticationHandler.class.getName());
     System.setProperty("solr.kerberos.cookie.domain", "127.0.0.1");
 
     miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), buildJettyConfig("/solr"));
@@ -92,7 +90,6 @@ public class TestSolrCloudWithDelegationTokens extends SolrTestCaseJ4 {
     solrClientSecondary = null;
     System.clearProperty("authenticationPlugin");
     System.clearProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED);
-    System.clearProperty(KerberosPlugin.AUTH_HANDLER_PARAM);
     System.clearProperty("solr.kerberos.cookie.domain");
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f78f698a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
new file mode 100644
index 0000000..1839d32
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
@@ -0,0 +1,340 @@
+/*
+ * 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.cloud;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+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.client.solrj.response.CollectionAdminResponse;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.admin.CollectionsHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.security.HttpParamDelegationTokenPlugin;
+import org.apache.solr.security.KerberosPlugin;
+import org.apache.solr.servlet.SolrRequestParsers;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.apache.solr.security.HttpParamDelegationTokenPlugin.USER_PARAM;
+import static org.apache.solr.security.HttpParamDelegationTokenPlugin.REMOTE_HOST_PARAM;
+import static org.apache.solr.security.HttpParamDelegationTokenPlugin.REMOTE_ADDRESS_PARAM;
+
+public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
+  private static final int NUM_SERVERS = 2;
+  private static MiniSolrCloudCluster miniCluster;
+  private static SolrClient solrClient;
+
+  private static String getUsersFirstGroup() throws Exception {
+    org.apache.hadoop.security.Groups hGroups =
+        new org.apache.hadoop.security.Groups(new Configuration());
+    List<String> g = hGroups.getGroups(System.getProperty("user.name"));
+    return g.get(0);
+  }
+
+  private static Map<String, String> getImpersonatorSettings() throws Exception {
+    Map<String, String> filterProps = new TreeMap<String, String>();
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "noGroups.hosts", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostAnyUser.groups", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostAnyUser.hosts", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "wrongHost.hosts", "1.1.1.1.1.1");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "wrongHost.groups", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "noHosts.groups", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "localHostAnyGroup.groups", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "localHostAnyGroup.hosts", "127.0.0.1");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostUsersGroup.groups", getUsersFirstGroup());
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "anyHostUsersGroup.hosts", "*");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "bogusGroup.groups", "__some_bogus_group");
+    filterProps.put(KerberosPlugin.IMPERSONATOR_PREFIX + "bogusGroup.hosts", "*");
+    return filterProps;
+  }
+
+  @BeforeClass
+  public static void startup() throws Exception {
+    System.setProperty("authenticationPlugin", HttpParamDelegationTokenPlugin.class.getName());
+    System.setProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED, "true");
+
+    System.setProperty("solr.kerberos.cookie.domain", "127.0.0.1");
+    Map<String, String> impSettings = getImpersonatorSettings();
+    for (Map.Entry<String, String> entry : impSettings.entrySet()) {
+      System.setProperty(entry.getKey(), entry.getValue());
+    }
+    System.setProperty("solr.test.sys.prop1", "propone");
+    System.setProperty("solr.test.sys.prop2", "proptwo");
+
+    SolrRequestParsers.DEFAULT.setAddRequestHeadersToContext(true);
+    String solrXml = MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML.replace("</solr>",
+        " <str name=\"collectionsHandler\">" + ImpersonatorCollectionsHandler.class.getName() + "</str>\n" +
+            "</solr>");
+
+    miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), solrXml, buildJettyConfig("/solr"));
+    JettySolrRunner runner = miniCluster.getJettySolrRunners().get(0);
+    solrClient = new HttpSolrClient.Builder(runner.getBaseUrl().toString()).build();
+  }
+
+  /**
+   * Verify that impersonator info is preserved in the request
+   */
+  public static class ImpersonatorCollectionsHandler extends CollectionsHandler {
+    public static AtomicBoolean called = new AtomicBoolean(false);
+
+    public ImpersonatorCollectionsHandler() { super(); }
+
+    public ImpersonatorCollectionsHandler(final CoreContainer coreContainer) {
+      super(coreContainer);
+    }
+
+    @Override
+    public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+      called.set(true);
+      super.handleRequestBody(req, rsp);
+      String doAs = req.getParams().get(KerberosPlugin.IMPERSONATOR_DO_AS_HTTP_PARAM);
+      if (doAs != null) {
+        HttpServletRequest httpRequest = (HttpServletRequest)req.getContext().get("httpRequest");
+        assertNotNull(httpRequest);
+        String user = (String)httpRequest.getAttribute(USER_PARAM);
+        assertNotNull(user);
+        assertEquals(user, httpRequest.getAttribute(KerberosPlugin.IMPERSONATOR_USER_NAME));
+      }
+    }
+  }
+
+  @AfterClass
+  public static void shutdown() throws Exception {
+    if (miniCluster != null) {
+      miniCluster.shutdown();
+    }
+    miniCluster = null;
+    solrClient.close();
+    solrClient = null;
+    System.clearProperty("authenticationPlugin");
+    System.clearProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED);
+    System.clearProperty("solr.kerberos.cookie.domain");
+    Map<String, String> impSettings = getImpersonatorSettings();
+    for (Map.Entry<String, String> entry : impSettings.entrySet()) {
+      System.clearProperty(entry.getKey());
+    }
+    System.clearProperty("solr.test.sys.prop1");
+    System.clearProperty("solr.test.sys.prop2");
+    SolrRequestParsers.DEFAULT.setAddRequestHeadersToContext(false);
+  }
+
+  private void create1ShardCollection(String name, String config, MiniSolrCloudCluster solrCluster) throws Exception {
+    CollectionAdminResponse response;
+    CollectionAdminRequest.Create create = new CollectionAdminRequest.Create() {
+      @Override
+      public SolrParams getParams() {
+        ModifiableSolrParams msp = new ModifiableSolrParams(super.getParams());
+        msp.set(USER_PARAM, "user");
+        return msp;
+      }
+    };
+    create.setConfigName(config);
+    create.setCollectionName(name);
+    create.setNumShards(1);
+    create.setReplicationFactor(1);
+    create.setMaxShardsPerNode(1);
+    response = create.process(solrCluster.getSolrClient());
+
+    if (response.getStatus() != 0 || response.getErrorMessages() != null) {
+      fail("Could not create collection. Response" + response.toString());
+    }
+    ZkStateReader zkStateReader = solrCluster.getSolrClient().getZkStateReader();
+    AbstractDistribZkTestBase.waitForRecoveriesToFinish(name, zkStateReader, false, true, 100);
+  }
+
+  private SolrRequest getProxyRequest(String user, String doAs) {
+    return getProxyRequest(user, doAs, null);
+  }
+
+  private SolrRequest getProxyRequest(String user, String doAs, String remoteHost) {
+    return getProxyRequest(user, doAs, remoteHost, null);
+  }
+
+  private SolrRequest getProxyRequest(String user, String doAs, String remoteHost, String remoteAddress) {
+    return new CollectionAdminRequest.List() {
+      @Override
+      public SolrParams getParams() {
+        ModifiableSolrParams params = new ModifiableSolrParams(super.getParams());
+        params.set(USER_PARAM, user);
+        params.set(KerberosPlugin.IMPERSONATOR_DO_AS_HTTP_PARAM, doAs);
+        if (remoteHost != null) params.set(REMOTE_HOST_PARAM, remoteHost);
+        if (remoteAddress != null) params.set(REMOTE_ADDRESS_PARAM, remoteAddress);
+        return params;
+      }
+    };
+  }
+
+  private String getExpectedGroupExMsg(String user, String doAs) {
+    return "User: " + user + " is not allowed to impersonate " + doAs;
+  }
+
+  private String getExpectedHostExMsg(String user) {
+    return "Unauthorized connection for super-user: " + user;
+  }
+
+  @Test
+  public void testProxyNoConfigGroups() throws Exception {
+    try {
+      solrClient.request(getProxyRequest("noGroups","bar"));
+      fail("Expected RemoteSolrException");
+    }
+    catch (HttpSolrClient.RemoteSolrException ex) {
+      assertTrue(ex.getMessage().contains(getExpectedGroupExMsg("noGroups", "bar")));
+    }
+  }
+
+  @Test
+  public void testProxyWrongHost() throws Exception {
+    try {
+      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.request(getProxyRequest("noHosts","bar"));
+      fail("Expected RemoteSolrException");
+    }
+    catch (HttpSolrClient.RemoteSolrException ex) {
+      // FixMe: this should return an exception about the host being invalid,
+      // but a bug (HADOOP-11077) causes an NPE instead.
+      //assertTrue(ex.getMessage().contains(getExpectedHostExMsg("noHosts")));
+    }
+  }
+
+  @Test
+  public void testProxyValidateAnyHostAnyUser() throws Exception {
+    solrClient.request(getProxyRequest("anyHostAnyUser", "bar", null));
+    assertTrue(ImpersonatorCollectionsHandler.called.get());
+  }
+
+  @Test
+  public void testProxyInvalidProxyUser() throws Exception {
+    try {
+      // 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 {
+    solrClient.request(getProxyRequest("localHostAnyGroup", "bar"));
+    assertTrue(ImpersonatorCollectionsHandler.called.get());
+  }
+
+
+
+  @Test
+  public void testProxyValidateGroup() throws Exception {
+    solrClient.request(getProxyRequest("anyHostUsersGroup", System.getProperty("user.name"), null));
+    assertTrue(ImpersonatorCollectionsHandler.called.get());
+  }
+
+  @Test
+  public void testProxyUnknownRemote() throws Exception {
+    try {
+      // Use a reserved ip address
+      String nonProxyUserConfiguredIpAddress = "255.255.255.255";
+      solrClient.request(getProxyRequest("localHostAnyGroup", "bar", "unknownhost.bar.foo", nonProxyUserConfiguredIpAddress));
+      fail("Expected RemoteSolrException");
+    }
+    catch (HttpSolrClient.RemoteSolrException ex) {
+      assertTrue(ex.getMessage().contains(getExpectedHostExMsg("localHostAnyGroup")));
+    }
+  }
+
+  @Test
+  public void testProxyInvalidRemote() throws Exception {
+    try {
+      String invalidIpAddress = "-127.-128";
+      solrClient.request(getProxyRequest("localHostAnyGroup","bar", "[ff01::114]", invalidIpAddress));
+      fail("Expected RemoteSolrException");
+    }
+    catch (HttpSolrClient.RemoteSolrException ex) {
+      assertTrue(ex.getMessage().contains(getExpectedHostExMsg("localHostAnyGroup")));
+    }
+  }
+
+  @Test
+  public void testProxyInvalidGroup() throws Exception {
+    try {
+      solrClient.request(getProxyRequest("bogusGroup","bar", null));
+      fail("Expected RemoteSolrException");
+    }
+    catch (HttpSolrClient.RemoteSolrException ex) {
+      assertTrue(ex.getMessage().contains(getExpectedGroupExMsg("bogusGroup", "bar")));
+    }
+  }
+
+  @Test
+  public void testProxyNullProxyUser() throws Exception {
+    try {
+      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
+  public void testForwarding() throws Exception {
+    String collectionName = "forwardingCollection";
+    File configDir = getFile("solr").toPath().resolve("collection1/conf").toFile();
+    miniCluster.uploadConfigDir(configDir, "conf1");
+    create1ShardCollection(collectionName, "conf1", miniCluster);
+
+    // try a command to each node, one of them must be forwarded
+    for (JettySolrRunner jetty : miniCluster.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/f78f698a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenAuthenticationHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenAuthenticationHandler.java b/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenAuthenticationHandler.java
deleted file mode 100644
index 7c5c94a..0000000
--- a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenAuthenticationHandler.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.hadoop.security.authentication.client.AuthenticationException;
-import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
-import org.apache.hadoop.security.authentication.server.AuthenticationToken;
-import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationHandler;
-
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
-
-/**
- * AuthenticationHandler that supports delegation tokens and simple
- * authentication via the "user" http parameter
- */
-public class HttpParamDelegationTokenAuthenticationHandler extends
-    DelegationTokenAuthenticationHandler {
-
-  public static final String USER_PARAM = "user";
-
-  public HttpParamDelegationTokenAuthenticationHandler() {
-    super(new HttpParamAuthenticationHandler());
-  }
-
-  @Override
-  public void init(Properties config) throws ServletException {
-    Properties conf = new Properties();
-    for (Map.Entry entry : config.entrySet()) {
-      conf.setProperty((String) entry.getKey(), (String) entry.getValue());
-    }
-    conf.setProperty(TOKEN_KIND, KerberosPlugin.DELEGATION_TOKEN_TYPE_DEFAULT);
-    super.init(conf);
-  }
- 
-  private static String getHttpParam(HttpServletRequest request, String param) {
-    List<NameValuePair> pairs =
-      URLEncodedUtils.parse(request.getQueryString(), Charset.forName("UTF-8"));
-    for (NameValuePair nvp : pairs) {
-      if(param.equals(nvp.getName())) {
-        return nvp.getValue();
-      }
-    }
-    return null;
-  }
-
-  private static class HttpParamAuthenticationHandler
-      implements AuthenticationHandler {
-
-    @Override
-    public String getType() {
-      return "dummy";
-    }
-
-    @Override
-    public void init(Properties config) throws ServletException {
-    }
-
-    @Override
-    public void destroy() {
-    }
-
-    @Override
-    public boolean managementOperation(AuthenticationToken token,
-        HttpServletRequest request, HttpServletResponse response)
-        throws IOException, AuthenticationException {
-      return false;
-    }
-
-    @Override
-    public AuthenticationToken authenticate(HttpServletRequest request,
-        HttpServletResponse response)
-        throws IOException, AuthenticationException {
-      AuthenticationToken token = null;
-      String userName = getHttpParam(request, USER_PARAM);
-      if (userName != null) {
-        return new AuthenticationToken(userName, userName, "test");
-      } else {
-        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-        response.setHeader("WWW-Authenticate", "dummy");
-      }
-      return token;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f78f698a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java b/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
new file mode 100644
index 0000000..7a4f69f
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
@@ -0,0 +1,272 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
+import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
+import org.apache.hadoop.security.authentication.server.AuthenticationToken;
+import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationHandler;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.protocol.HttpContext;
+import org.apache.solr.client.solrj.impl.HttpClientUtil;
+import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.request.SolrRequestInfo;
+
+/**
+ * AuthenticationHandler that supports delegation tokens and simple
+ * authentication via the "user" http parameter
+ */
+public class HttpParamDelegationTokenPlugin extends KerberosPlugin {
+  public static final String USER_PARAM = "user"; // http parameter for user authentication
+  public static final String REMOTE_HOST_PARAM = "remoteHost"; // http parameter for indicating remote host
+  public static final String REMOTE_ADDRESS_PARAM = "remoteAddress"; // http parameter for indicating remote address
+  public static final String INTERNAL_REQUEST_HEADER = "internalRequest"; // http header for indicating internal request
+
+  boolean isSolrThread() {
+    return ExecutorUtil.isSolrServerThread();
+  }
+
+  private final HttpRequestInterceptor interceptor = new HttpRequestInterceptor() {
+    @Override
+    public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {
+      SolrRequestInfo reqInfo = SolrRequestInfo.getRequestInfo();
+      String usr;
+      if (reqInfo != null) {
+        Principal principal = reqInfo.getReq().getUserPrincipal();
+        if (principal == null) {
+          //this had a request but not authenticated
+          //so we don't not need to set a principal
+          return;
+        } else {
+          usr = principal.getName();
+        }
+      } else {
+        if (!isSolrThread()) {
+          //if this is not running inside a Solr threadpool (as in testcases)
+          // then no need to add any header
+          return;
+        }
+        //this request seems to be originated from Solr itself
+        usr = "$"; //special name to denote the user is the node itself
+      }
+      httpRequest.setHeader(INTERNAL_REQUEST_HEADER, usr);
+    }
+  };
+
+  public HttpParamDelegationTokenPlugin(CoreContainer coreContainer) {
+    super(coreContainer);
+  }
+
+  @Override
+  public void init(Map<String, Object> pluginConfig) {
+    try {
+      final FilterConfig initConf = getInitFilterConfig(pluginConfig, true);
+
+      FilterConfig conf = new FilterConfig() {
+        @Override
+        public ServletContext getServletContext() {
+          return initConf.getServletContext();
+        }
+
+        @Override
+        public Enumeration<String> getInitParameterNames() {
+          return initConf.getInitParameterNames();
+        }
+
+        @Override
+        public String getInitParameter(String param) {
+          if (AuthenticationFilter.AUTH_TYPE.equals(param)) {
+            return HttpParamDelegationTokenAuthenticationHandler.class.getName();
+          }
+          return initConf.getInitParameter(param);
+        }
+
+        @Override
+        public String getFilterName() {
+         return "HttpParamFilter";
+        }
+      };
+      Filter kerberosFilter = new HttpParamToRequestFilter();
+      kerberosFilter.init(conf);
+      setKerberosFilter(kerberosFilter);
+    } catch (ServletException e) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+          "Error initializing kerberos authentication plugin: "+e);
+    }
+  }
+
+  @Override
+  public SolrHttpClientBuilder getHttpClientBuilder(SolrHttpClientBuilder builder) {
+    HttpClientUtil.addRequestInterceptor(interceptor);
+    return super.getHttpClientBuilder(builder);
+  }
+
+  @Override
+  public void close() {
+    HttpClientUtil.removeRequestInterceptor(interceptor);
+    super.close();
+  }
+
+  private static String getHttpParam(HttpServletRequest request, String param) {
+    List<NameValuePair> pairs = URLEncodedUtils.parse(request.getQueryString(), Charset.forName("UTF-8"));
+    for (NameValuePair nvp : pairs) {
+      if (param.equals(nvp.getName())) {
+        return nvp.getValue();
+      }
+    }
+    return null;
+  }
+
+  public static class HttpParamDelegationTokenAuthenticationHandler extends
+      DelegationTokenAuthenticationHandler {
+
+    public HttpParamDelegationTokenAuthenticationHandler() {
+      super(new HttpParamAuthenticationHandler());
+    }
+
+    @Override
+    public void init(Properties config) throws ServletException {
+      Properties conf = new Properties();
+      for (Map.Entry entry : config.entrySet()) {
+        conf.setProperty((String) entry.getKey(), (String) entry.getValue());
+      }
+      conf.setProperty(TOKEN_KIND, KerberosPlugin.DELEGATION_TOKEN_TYPE_DEFAULT);
+      super.init(conf);
+    }
+
+    private static class HttpParamAuthenticationHandler implements AuthenticationHandler {
+      @Override
+      public String getType() {
+        return "dummy";
+      }
+
+      @Override
+      public void init(Properties config) throws ServletException {
+      }
+
+      @Override
+      public void destroy() {
+      }
+
+      @Override
+      public boolean managementOperation(AuthenticationToken token,
+                                         HttpServletRequest request, HttpServletResponse response)
+          throws IOException, AuthenticationException {
+        return false;
+      }
+
+      @Override
+      public AuthenticationToken authenticate(HttpServletRequest request,
+                                              HttpServletResponse response)
+          throws IOException, AuthenticationException {
+        AuthenticationToken token = null;
+        String userName = getHttpParam(request, USER_PARAM);
+        if (userName == null) {
+          //check if this is an internal request
+          userName = request.getHeader(INTERNAL_REQUEST_HEADER);
+        }
+        if (userName != null) {
+          return new AuthenticationToken(userName, userName, "test");
+        } else {
+          response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+          response.setHeader("WWW-Authenticate", "dummy");
+        }
+        return token;
+      }
+    }
+  }
+
+  /**
+   * Filter that converts http params to HttpServletRequest params
+   */
+  private static class HttpParamToRequestFilter extends DelegationTokenKerberosFilter {
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+      final HttpServletRequest httpRequest = (HttpServletRequest) request;
+      final HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest) {
+        @Override
+        public String getRemoteHost() {
+          String param = getHttpParam(httpRequest, REMOTE_HOST_PARAM);
+          return param != null ? param : httpRequest.getRemoteHost();
+        }
+
+        @Override
+        public String getRemoteAddr() {
+          String param = getHttpParam(httpRequest, REMOTE_ADDRESS_PARAM);
+          return param != null ? param : httpRequest.getRemoteAddr();
+        }
+      };
+
+      super.doFilter(requestWrapper, response, chain);
+    }
+
+    @Override
+    protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+                            HttpServletResponse response) throws IOException, ServletException {
+      // remove the filter-specific authentication information, so it doesn't get accidentally forwarded.
+      List<NameValuePair> newPairs = new LinkedList<NameValuePair>();
+      List<NameValuePair> pairs = URLEncodedUtils.parse(request.getQueryString(), Charset.forName("UTF-8"));
+      for (NameValuePair nvp : pairs) {
+        if (!USER_PARAM.equals(nvp.getName())) {
+          newPairs.add(nvp);
+        }
+        else {
+          request.setAttribute(USER_PARAM, nvp.getValue());
+        }
+      }
+      final String queryStringNoUser = URLEncodedUtils.format(newPairs, StandardCharsets.UTF_8);
+      HttpServletRequest requestWrapper = new HttpServletRequestWrapper(request) {
+        @Override
+        public String getQueryString() {
+          return queryStringNoUser;
+        }
+      };
+      super.doFilter(filterChain, requestWrapper, response);
+    }
+  }
+}


[5/5] lucene-solr:branch_6x: SOLR-9324 Fix TestSolrCloudWithSecureImpersonation#testForwarding

Posted by yo...@apache.org.
SOLR-9324 Fix TestSolrCloudWithSecureImpersonation#testForwarding


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f084e658
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f084e658
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f084e658

Branch: refs/heads/branch_6x
Commit: f084e658b77e1ec98021146318cc37772b73de51
Parents: 6428772
Author: Hrishikesh Gadre <hg...@cloudera.com>
Authored: Tue Nov 15 16:32:21 2016 -0800
Committer: yonik <yo...@apache.org>
Committed: Thu Nov 17 15:05:47 2016 -0500

----------------------------------------------------------------------
 .../cloud/TestSolrCloudWithSecureImpersonation.java  |  2 +-
 .../security/HttpParamDelegationTokenPlugin.java     | 15 +++++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f084e658/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
index ef41e4d..8d7a1a6 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
@@ -343,7 +343,7 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
   @Test
   public void testForwarding() throws Exception {
     String collectionName = "forwardingCollection";
-    File configDir = getFile("solr").toPath().resolve("collection1/conf").toFile();
+    File configDir = TEST_PATH().resolve("collection1/conf").toFile();
     miniCluster.uploadConfigDir(configDir, "conf1");
     create1ShardCollection(collectionName, "conf1", miniCluster);
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f084e658/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java b/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
index 7a4f69f..42d99a2 100644
--- a/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
+++ b/solr/core/src/test/org/apache/solr/security/HttpParamDelegationTokenPlugin.java
@@ -49,8 +49,9 @@ import org.apache.http.HttpRequestInterceptor;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.protocol.HttpContext;
+import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
-import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder;
+import org.apache.solr.client.solrj.impl.Krb5HttpClientConfigurer;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.core.CoreContainer;
@@ -97,6 +98,13 @@ public class HttpParamDelegationTokenPlugin extends KerberosPlugin {
     }
   };
 
+  private final HttpClientConfigurer configurer = new Krb5HttpClientConfigurer() {
+    public void configure(org.apache.http.impl.client.DefaultHttpClient httpClient, org.apache.solr.common.params.SolrParams config) {
+      super.configure(httpClient, config);
+      httpClient.addRequestInterceptor(interceptor);
+    };
+  };
+
   public HttpParamDelegationTokenPlugin(CoreContainer coreContainer) {
     super(coreContainer);
   }
@@ -140,9 +148,8 @@ public class HttpParamDelegationTokenPlugin extends KerberosPlugin {
   }
 
   @Override
-  public SolrHttpClientBuilder getHttpClientBuilder(SolrHttpClientBuilder builder) {
-    HttpClientUtil.addRequestInterceptor(interceptor);
-    return super.getHttpClientBuilder(builder);
+  public HttpClientConfigurer getClientConfigurer() {
+    return configurer;
   }
 
   @Override


[2/5] lucene-solr:branch_6x: SOLR-9460: Disable test that does not work with Windows

Posted by yo...@apache.org.
SOLR-9460: Disable test that does not work with Windows


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/225198a2
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/225198a2
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/225198a2

Branch: refs/heads/branch_6x
Commit: 225198a2b754783d485b2cee7d1aa4741f65e5a3
Parents: 8659fe1
Author: Uwe Schindler <us...@apache.org>
Authored: Sat Sep 3 10:48:01 2016 +0200
Committer: yonik <yo...@apache.org>
Committed: Thu Nov 17 15:05:46 2016 -0500

----------------------------------------------------------------------
 .../apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java   | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/225198a2/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
index 71107ee..3727620 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithSecureImpersonation.java
@@ -25,6 +25,7 @@ import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.hadoop.conf.Configuration;
+import org.apache.lucene.util.Constants;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrRequest;
@@ -92,6 +93,8 @@ public class TestSolrCloudWithSecureImpersonation extends SolrTestCaseJ4 {
 
   @BeforeClass
   public static void startup() throws Exception {
+    assumeFalse("Hadoop does not work on Windows", Constants.WINDOWS);
+    
     System.setProperty("authenticationPlugin", HttpParamDelegationTokenPlugin.class.getName());
     System.setProperty(KerberosPlugin.DELEGATION_TOKEN_ENABLED, "true");