You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2016/10/03 18:49:32 UTC

lucene-solr:master: SOLR-9520: Kerberos delegation support in SolrJ

Repository: lucene-solr
Updated Branches:
  refs/heads/master e7ade287e -> 3a76ef119


SOLR-9520: Kerberos delegation support in SolrJ


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

Branch: refs/heads/master
Commit: 3a76ef11931d6cf5e86002d9c23f03c79f663fc0
Parents: e7ade28
Author: Noble Paul <no...@apache.org>
Authored: Tue Oct 4 00:19:20 2016 +0530
Committer: Noble Paul <no...@apache.org>
Committed: Tue Oct 4 00:19:20 2016 +0530

----------------------------------------------------------------------
 solr/CHANGES.txt                                |  1 +
 .../TestSolrCloudWithDelegationTokens.java      | 26 ++++--
 .../solr/client/solrj/impl/CloudSolrClient.java | 46 +++++++---
 .../solr/client/solrj/impl/HttpSolrClient.java  | 59 ++++--------
 .../client/solrj/impl/LBHttpSolrClient.java     | 94 ++++++++++++++------
 5 files changed, 138 insertions(+), 88 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a76ef11/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index b402625..bbcc42b 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -115,6 +115,7 @@ New Features
 * SOLR-9205: Added method LukeResponse.getSchemaFlags() which returns field
   information as an EnumSet (Fengtan, Alan Woodward)
 
+* SOLR-9520: Kerberos delegation support in SolrJ (Ishan Chattopadhyaya, noble)
 
 Bug Fixes
 ----------------------

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a76ef11/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 a58ec8c..c3fa813 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithDelegationTokens.java
@@ -20,7 +20,10 @@ import junit.framework.Assert;
 import org.apache.hadoop.util.Time;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.LBHttpSolrClient;
+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.request.CollectionAdminRequest;
@@ -171,30 +174,39 @@ public class TestSolrCloudWithDelegationTokens extends SolrTestCaseJ4 {
 
   private int getStatusCode(String token, final String user, final String op, HttpSolrClient client)
   throws Exception {
-    HttpSolrClient delegationTokenServer =
-        new HttpSolrClient.Builder(client.getBaseURL().toString())
-            .withDelegationToken(token)
+    SolrClient delegationTokenClient;
+    if (random().nextBoolean()) delegationTokenClient = new HttpSolrClient.Builder(client.getBaseURL().toString())
+        .withKerberosDelegationToken(token)
+        .withResponseParser(client.getParser())
+        .build();
+    else delegationTokenClient = new CloudSolrClient.Builder()
+        .withZkHost((miniCluster.getZkServer().getZkAddress()))
+        .withLBHttpSolrClientBuilder(new LBHttpSolrClient.Builder()
             .withResponseParser(client.getParser())
-            .build();
+            .withHttpSolrClientBuilder(
+                new HttpSolrClient.Builder()
+                    .withKerberosDelegationToken(token)
+            ))
+        .build();
     try {
       ModifiableSolrParams p = new ModifiableSolrParams();
       if (user != null) p.set(USER_PARAM, user);
       if (op != null) p.set("op", op);
       SolrRequest req = getAdminRequest(p);
       if (user != null || op != null) {
-        Set<String> queryParams = new HashSet<String>();
+        Set<String> queryParams = new HashSet<>();
         if (user != null) queryParams.add(USER_PARAM);
         if (op != null) queryParams.add("op");
         req.setQueryParams(queryParams);
       }
       try {
-        delegationTokenServer.request(req, null, null);
+        delegationTokenClient.request(req, null);
         return HttpStatus.SC_OK;
       } catch (HttpSolrClient.RemoteSolrException re) {
         return re.code();
       }
     } finally {
-      delegationTokenServer.close();
+      delegationTokenClient.close();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a76ef11/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
index 834e956..6a186ce 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
@@ -341,7 +341,7 @@ public class CloudSolrClient extends SolrClient {
    *          the {@link HttpClient} instance to be used for all requests. The provided httpClient should use a
    *          multi-threaded connection manager.  If null, a default HttpClient will be used.
    * @param lbSolrClient
-   *          LBHttpSolrServer instance for requests.  If null, a default HttpClient will be used.
+   *          LBHttpSolrClient instance for requests.  If null, a default LBHttpSolrClient will be used.
    * @param updatesToLeaders
    *          If true, sends updates to shard leaders.
    *
@@ -350,7 +350,7 @@ public class CloudSolrClient extends SolrClient {
    */
   @Deprecated
   public CloudSolrClient(Collection<String> zkHosts, String chroot, HttpClient httpClient, LBHttpSolrClient lbSolrClient, boolean updatesToLeaders) {
-    this(zkHosts, chroot, httpClient, lbSolrClient, updatesToLeaders, false);
+    this(zkHosts, chroot, httpClient, lbSolrClient, null, updatesToLeaders, false);
   }
 
   /**
@@ -371,23 +371,31 @@ public class CloudSolrClient extends SolrClient {
    *          the {@link HttpClient} instance to be used for all requests. The provided httpClient should use a
    *          multi-threaded connection manager.  If null, a default HttpClient will be used.
    * @param lbSolrClient
-   *          LBHttpSolrServer instance for requests.  If null, a default HttpClient will be used.
+   *          LBHttpSolrClient instance for requests.  If null, a default LBHttpSolrClient will be used.
+   * @param lbHttpSolrClientBuilder
+   *          LBHttpSolrClient builder to construct the LBHttpSolrClient. If null, a default builder will be used.
    * @param updatesToLeaders
    *          If true, sends updates to shard leaders.
    * @param directUpdatesToLeadersOnly
    *          If true, sends direct updates to shard leaders only.
    */
-  private CloudSolrClient(Collection<String> zkHosts, String chroot, HttpClient httpClient, LBHttpSolrClient lbSolrClient,
-      boolean updatesToLeaders, boolean directUpdatesToLeadersOnly) {
+  private CloudSolrClient(Collection<String> zkHosts,
+                          String chroot,
+                          HttpClient httpClient,
+                          LBHttpSolrClient lbSolrClient,
+                          LBHttpSolrClient.Builder lbHttpSolrClientBuilder,
+                          boolean updatesToLeaders,
+                          boolean directUpdatesToLeadersOnly) {
+    this.clientIsInternal = httpClient == null;
+    this.shutdownLBHttpSolrServer = lbSolrClient == null;
+    if(lbHttpSolrClientBuilder != null) lbSolrClient = lbHttpSolrClientBuilder.build();
+    if(lbSolrClient != null) httpClient = lbSolrClient.getHttpClient();
+    this.myClient = httpClient == null ? HttpClientUtil.createClient(null) : httpClient;
+    if (lbSolrClient == null) lbSolrClient = createLBHttpSolrClient(myClient);
+    this.lbClient = lbSolrClient;
     this.zkHost = buildZkHostString(zkHosts, chroot);
     this.updatesToLeaders = updatesToLeaders;
     this.directUpdatesToLeadersOnly = directUpdatesToLeadersOnly;
-    
-    this.clientIsInternal = httpClient == null;
-    this.myClient = httpClient == null ? HttpClientUtil.createClient(null) : httpClient;
-    
-    this.shutdownLBHttpSolrServer = lbSolrClient == null;
-    this.lbClient = lbSolrClient == null ? createLBHttpSolrClient(myClient) : lbSolrClient;
   }
   
   /**
@@ -475,7 +483,7 @@ public class CloudSolrClient extends SolrClient {
   public ResponseParser getParser() {
     return lbClient.getParser();
   }
-  
+
   /**
    * Note: This setter method is <b>not thread-safe</b>.
    * 
@@ -1553,6 +1561,7 @@ public class CloudSolrClient extends SolrClient {
     private HttpClient httpClient;
     private String zkChroot;
     private LBHttpSolrClient loadBalancedSolrClient;
+    private LBHttpSolrClient.Builder lbClientBuilder;
     private boolean shardLeadersOnly;
     private boolean directUpdatesToLeadersOnly;
     
@@ -1578,11 +1587,20 @@ public class CloudSolrClient extends SolrClient {
     /**
      * Provides a {@link HttpClient} for the builder to use when creating clients.
      */
+    public Builder withLBHttpSolrClientBuilder(LBHttpSolrClient.Builder lbHttpSolrClientBuilder) {
+      this.lbClientBuilder = lbHttpSolrClientBuilder;
+      return this;
+    }
+
+    /**
+     * Provides a {@link HttpClient} for the builder to use when creating clients.
+     */
     public Builder withHttpClient(HttpClient httpClient) {
       this.httpClient = httpClient;
       return this;
     }
-    
+
+
     /**
      * Provide a series of ZooKeeper client endpoints for the builder to use when creating clients.
      * 
@@ -1652,7 +1670,7 @@ public class CloudSolrClient extends SolrClient {
      * Create a {@link CloudSolrClient} based on the provided configuration.
      */
     public CloudSolrClient build() {
-      return new CloudSolrClient(zkHosts, zkChroot, httpClient, loadBalancedSolrClient,
+      return new CloudSolrClient(zkHosts, zkChroot, httpClient, loadBalancedSolrClient, lbClientBuilder,
           shardLeadersOnly, directUpdatesToLeadersOnly);
     }
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a76ef11/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
index 222119c..e43fd33 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
@@ -23,7 +23,6 @@ import java.lang.invoke.MethodHandles;
 import java.net.ConnectException;
 import java.net.SocketTimeoutException;
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -31,7 +30,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
@@ -746,43 +744,6 @@ public class HttpSolrClient extends SolrClient {
     }
   }
 
-  private static class DelegationTokenHttpSolrClient extends HttpSolrClient {
-    private final String DELEGATION_TOKEN_PARAM = "delegation";
-    private final String delegationToken;
-
-    public DelegationTokenHttpSolrClient(String baseURL,
-                                         HttpClient client,
-                                         ResponseParser parser,
-                                         boolean allowCompression,
-                                         String delegationToken) {
-      super(baseURL, client, parser, allowCompression);
-      if (delegationToken == null) {
-        throw new IllegalArgumentException("Delegation token cannot be null");
-      }
-      this.delegationToken = delegationToken;
-      setQueryParams(new TreeSet<String>(Arrays.asList(DELEGATION_TOKEN_PARAM)));
-      invariantParams = new ModifiableSolrParams();
-      invariantParams.set(DELEGATION_TOKEN_PARAM, delegationToken);
-    }
-
-    @Override
-    protected HttpRequestBase createMethod(final SolrRequest request, String collection) throws IOException, SolrServerException {
-      SolrParams params = request.getParams();
-      if (params.getParams(DELEGATION_TOKEN_PARAM) != null) {
-        throw new IllegalArgumentException(DELEGATION_TOKEN_PARAM + " parameter not supported");
-      }
-      return super.createMethod(request, collection);
-    }
-
-    @Override
-    public void setQueryParams(Set<String> queryParams) {
-      if (queryParams == null || !queryParams.contains(DELEGATION_TOKEN_PARAM)) {
-        throw new IllegalArgumentException("Query params must contain " + DELEGATION_TOKEN_PARAM);
-      }
-      super.setQueryParams(queryParams);
-    }
-  }
-
   /**
    * Constructs {@link HttpSolrClient} instances from provided configuration.
    */
@@ -792,7 +753,16 @@ public class HttpSolrClient extends SolrClient {
     private ResponseParser responseParser;
     private boolean compression;
     private String delegationToken;
-    
+
+    public Builder() {
+      this.responseParser = new BinaryResponseParser();
+    }
+
+    public Builder withBaseSolrUrl(String baseSolrUrl) {
+      this.baseSolrUrl = baseSolrUrl;
+      return this;
+    }
+
     /**
      * Create a Builder object, based on the provided Solr URL.
      * 
@@ -832,6 +802,15 @@ public class HttpSolrClient extends SolrClient {
     /**
      * Use a delegation token for authenticating via the KerberosPlugin
      */
+    public Builder withKerberosDelegationToken(String delegationToken) {
+      this.delegationToken = delegationToken;
+      return this;
+    }
+
+    @Deprecated
+    /**
+     * @deprecated use {@link withKerberosDelegationToken(String)} instead
+     */
     public Builder withDelegationToken(String delegationToken) {
       this.delegationToken = delegationToken;
       return this;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a76ef11/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
index 74b0943..3cb59cd 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBHttpSolrClient.java
@@ -118,6 +118,7 @@ public class LBHttpSolrClient extends SolrClient {
 
   private final HttpClient httpClient;
   private final boolean clientIsInternal;
+  private HttpSolrClient.Builder httpSolrClientBuilder;
   private final AtomicInteger counter = new AtomicInteger(-1);
 
   private static final SolrQuery solrQuery = new SolrQuery("*:*");
@@ -247,22 +248,30 @@ public class LBHttpSolrClient extends SolrClient {
    * @deprecated use {@link Builder} instead.  This will soon be a protected
    * method and will only be available for use in implementing subclasses.
    */
+  public LBHttpSolrClient(HttpSolrClient.Builder httpSolrClientBuilder,
+                          HttpClient httpClient, String... solrServerUrl) {
+    clientIsInternal = httpClient == null;
+    this.httpSolrClientBuilder = httpSolrClientBuilder;
+    httpClient = constructClient(null);
+    this.httpClient = httpClient;
+    if (solrServerUrl != null) {
+      for (String s : solrServerUrl) {
+        ServerWrapper wrapper = new ServerWrapper(makeSolrClient(s));
+        aliveServers.put(wrapper.getKey(), wrapper);
+      }
+    }
+    updateAliveList();
+  }
+
+  /**
+   * The provided httpClient should use a multi-threaded connection manager
+   * @deprecated use {@link Builder} instead.  This will soon be a protected
+   * method and will only be available for use in implementing subclasses.
+   */
   @Deprecated
   public LBHttpSolrClient(HttpClient httpClient, ResponseParser parser, String... solrServerUrl) {
     clientIsInternal = (httpClient == null);
-    if (httpClient == null) {
-      ModifiableSolrParams params = new ModifiableSolrParams();
-      if (solrServerUrl.length > 1) {
-        // we prefer retrying another server
-        params.set(HttpClientUtil.PROP_USE_RETRY, false);
-      } else {
-        params.set(HttpClientUtil.PROP_USE_RETRY, true);
-      }
-      this.httpClient = HttpClientUtil.createClient(params);
-    } else {
-      this.httpClient = httpClient;
-    }
-    
+    this.httpClient = httpClient == null ? constructClient(solrServerUrl) : httpClient;
     this.parser = parser;
     
     for (String s : solrServerUrl) {
@@ -271,7 +280,18 @@ public class LBHttpSolrClient extends SolrClient {
     }
     updateAliveList();
   }
-  
+
+  private HttpClient constructClient(String[] solrServerUrl) {
+    ModifiableSolrParams params = new ModifiableSolrParams();
+    if (solrServerUrl != null && solrServerUrl.length > 1) {
+      // we prefer retrying another server
+      params.set(HttpClientUtil.PROP_USE_RETRY, false);
+    } else {
+      params.set(HttpClientUtil.PROP_USE_RETRY, true);
+    }
+    return HttpClientUtil.createClient(params);
+  }
+
   public Set<String> getQueryParams() {
     return queryParams;
   }
@@ -294,15 +314,19 @@ public class LBHttpSolrClient extends SolrClient {
   }
 
   protected HttpSolrClient makeSolrClient(String server) {
-    HttpSolrClient client = new HttpSolrClient.Builder(server)
-        .withHttpClient(httpClient)
-        .withResponseParser(parser)
-        .build();
-    if (connectionTimeout != null) {
-      client.setConnectionTimeout(connectionTimeout);
-    }
-    if (soTimeout != null) {
-      client.setSoTimeout(soTimeout);
+    HttpSolrClient client;
+    if (httpSolrClientBuilder != null) {
+      synchronized (this) {
+        client = httpSolrClientBuilder
+            .withBaseSolrUrl(server)
+            .withHttpClient(httpClient)
+            .build();
+      }
+    } else {
+      client = new HttpSolrClient.Builder(server)
+          .withHttpClient(httpClient)
+          .withResponseParser(parser)
+          .build();
     }
     if (requestWriter != null) {
       client.setRequestWriter(requestWriter);
@@ -787,11 +811,16 @@ public class LBHttpSolrClient extends SolrClient {
     private final List<String> baseSolrUrls;
     private HttpClient httpClient;
     private ResponseParser responseParser;
-    
+    private HttpSolrClient.Builder httpSolrClientBuilder;
+
     public Builder() {
-      this.baseSolrUrls = new ArrayList<String>();
+      this.baseSolrUrls = new ArrayList<>();
       this.responseParser = new BinaryResponseParser();
     }
+
+    public HttpSolrClient.Builder getHttpSolrClientBuilder() {
+      return httpSolrClientBuilder;
+    }
     
     /**
      * Provide a Solr endpoint to be used when configuring {@link LBHttpSolrClient} instances.
@@ -831,13 +860,24 @@ public class LBHttpSolrClient extends SolrClient {
       this.responseParser = responseParser;
       return this;
     }
-    
+
+    /**
+     * Provides a {@link HttpSolrClient.Builder} to be used for building the internally used clients.
+     */
+    public Builder withHttpSolrClientBuilder(HttpSolrClient.Builder builder) {
+      this.httpSolrClientBuilder = builder;
+      return this;
+    }
+
     /**
      * Create a {@link HttpSolrClient} based on provided configuration.
      */
     public LBHttpSolrClient build() {
       final String[] baseUrlArray = new String[baseSolrUrls.size()];
-      return new LBHttpSolrClient(httpClient, responseParser, baseSolrUrls.toArray(baseUrlArray));
+      String[] solrServerUrls = baseSolrUrls.toArray(baseUrlArray);
+      return httpSolrClientBuilder != null ?
+          new LBHttpSolrClient(httpSolrClientBuilder, httpClient, solrServerUrls) :
+          new LBHttpSolrClient(httpClient, responseParser, solrServerUrls);
     }
   }
 }