You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2018/10/03 14:18:53 UTC
[6/6] lucene-solr:solr12799-auth-forward: Forward the user principal
on inter-node requests
Forward the user principal on inter-node requests
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/c1851096
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/c1851096
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/c1851096
Branch: refs/heads/solr12799-auth-forward
Commit: c1851096f67c1722ed92439d38d62149d4827b9d
Parents: 4c32559
Author: Jan Høydahl <ja...@apache.org>
Authored: Wed Oct 3 15:57:16 2018 +0200
Committer: Jan Høydahl <ja...@apache.org>
Committed: Wed Oct 3 15:57:16 2018 +0200
----------------------------------------------------------------------
.../handler/component/HttpShardHandler.java | 7 +++++++
.../apache/solr/security/BasicAuthPlugin.java | 1 -
.../solr/security/PKIAuthenticationPlugin.java | 4 ++--
.../apache/solr/update/SolrCmdDistributor.java | 4 ++++
.../solr/security/BasicAuthIntegrationTest.java | 20 ++++++++++++++++++--
.../apache/solr/client/solrj/SolrRequest.java | 11 +++++++++++
.../solr/client/solrj/impl/HttpSolrClient.java | 13 ++++++++++---
7 files changed, 52 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java
index a548031..3068a36 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandler.java
@@ -18,6 +18,7 @@ package org.apache.solr.handler.component;
import java.lang.invoke.MethodHandles;
import java.net.ConnectException;
+import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -56,6 +57,7 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrRequestInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
@@ -136,6 +138,10 @@ public class HttpShardHandler extends ShardHandler {
// do this outside of the callable for thread safety reasons
final List<String> urls = getURLs(shard);
+ // If request has a Principal (authenticated user), extract it for passing on to the new shard request
+ SolrRequestInfo requestInfo = SolrRequestInfo.getRequestInfo();
+ final Principal userPrincipal = requestInfo == null ? null : requestInfo.getReq().getUserPrincipal();
+
Callable<ShardResponse> task = () -> {
ShardResponse srsp = new ShardResponse();
@@ -154,6 +160,7 @@ public class HttpShardHandler extends ShardHandler {
QueryRequest req = makeQueryRequest(sreq, params, shard);
req.setMethod(SolrRequest.METHOD.POST);
+ req.setUserPrincipal(userPrincipal);
// no need to set the response parser as binary is the default
// req.setResponseParser(new BinaryResponseParser());
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
index dc97828..4087600 100644
--- a/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/BasicAuthPlugin.java
@@ -197,7 +197,6 @@ public class BasicAuthPlugin extends AuthenticationPlugin implements ConfigEdita
if (forwardCredentials) {
if (httpContext instanceof HttpClientContext) {
HttpClientContext httpClientContext = (HttpClientContext) httpContext;
- log.info("*** HttpClientContext token={}", httpClientContext.getUserToken());
if (httpClientContext.getUserToken() instanceof BasicAuthUserPrincipal) {
BasicAuthUserPrincipal principal = (BasicAuthUserPrincipal) httpClientContext.getUserToken();
String userPassBase64 = Base64.encodeBase64String((principal.getName() + ":" + principal.getPassword()).getBytes(StandardCharsets.UTF_8));
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
index 2a8e216..5245afc 100644
--- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
@@ -239,10 +239,10 @@ public class PKIAuthenticationPlugin extends AuthenticationPlugin implements Htt
return;
}
if (!cores.getAuthenticationPlugin().interceptInternodeRequest(httpRequest, httpContext)) {
- log.debug("PKIAuthenticationPlugin secures this internode request");
+ log.debug("{} secures this internode request", this.getClass().getSimpleName());
setHeader(httpRequest);
} else {
- log.debug("{} secures this internode request", cores.getAuthenticationPlugin().getClass().getName());
+ log.debug("{} secures this internode request", cores.getAuthenticationPlugin().getClass().getSimpleName());
}
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java b/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
index cb7f9cb..af2b5aa 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
@@ -47,6 +47,7 @@ import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.Diagnostics;
+import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.update.processor.DistributedUpdateProcessor;
import org.apache.solr.update.processor.DistributedUpdateProcessor.LeaderRequestReplicationTracker;
import org.apache.solr.update.processor.DistributedUpdateProcessor.RollupRequestReplicationTracker;
@@ -282,6 +283,9 @@ public class SolrCmdDistributor implements Closeable {
}
private void submit(final Req req, boolean isCommit) {
+ // Copy user principal from the original request to the new update request, for later authentication interceptor use
+ req.uReq.setUserPrincipal(SolrRequestInfo.getRequestInfo().getReq().getUserPrincipal());
+
if (req.synchronous) {
blockAndDoRetries();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
index 581f4cf..0066914 100644
--- a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
@@ -46,9 +46,11 @@ import org.apache.solr.client.solrj.impl.HttpClientUtil;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.RequestWriter.StringPayloadContentWriter;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.request.V2Request;
+import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.cloud.DocCollection;
@@ -221,13 +223,18 @@ public class BasicAuthIntegrationTest extends SolrCloudTestCase {
log.error("RunExampleTool failed due to: " + e +
"; stdout from tool prior to failure: " + baos.toString(StandardCharsets.UTF_8.name()));
}
- executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: false}}", "harry", "HarryIsUberCool");
addDocument("harry","HarryIsUberCool","id", "5");
+ // Validate forwardCredentials
+ assertEquals(1, executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound());
+ // TODO: Validate that this requests were handled by PKI plugin
executeCommand(baseUrl + authcPrefix, cl, "{set-property : { forwardCredentials: true}}", "harry", "HarryIsUberCool");
verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication/forwardCredentials", "true", 20, "harry", "HarryIsUberCool");
- assertEquals(1, cluster.getSolrClient().query(COLLECTION, params("q", "id:5")).getResults().getNumFound());
+ assertEquals(1, executeQuery(params("q", "id:5"), "harry", "HarryIsUberCool").getResults().getNumFound());
+ // NOCOMMIT: Validate that sub requests were handled by BasicAuth plugin
+
+ executeCommand(baseUrl + authcPrefix, cl, "{set-property : { blockUnknown: false}}", "harry", "HarryIsUberCool");
} finally {
if (cl != null) {
HttpClientUtil.close(cl);
@@ -235,6 +242,15 @@ public class BasicAuthIntegrationTest extends SolrCloudTestCase {
}
}
+ private QueryResponse executeQuery(ModifiableSolrParams params, String user, String pass) throws IOException, SolrServerException {
+ SolrRequest req = new QueryRequest(params);
+ req.setBasicAuthCredentials(user, pass);
+ QueryResponse resp = (QueryResponse) req.process(cluster.getSolrClient(), COLLECTION);
+ assertNull(resp.getException());
+ assertEquals(0, resp.getStatus());
+ return resp;
+ }
+
private void addDocument(String user, String pass, String... fields) throws IOException, SolrServerException {
SolrInputDocument doc = new SolrInputDocument();
boolean isKey = true;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
index 7dbaab9..04b94f7 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
@@ -18,6 +18,7 @@ package org.apache.solr.client.solrj;
import java.io.IOException;
import java.io.Serializable;
+import java.security.Principal;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -36,6 +37,16 @@ import static java.util.Collections.unmodifiableSet;
* @since solr 1.3
*/
public abstract class SolrRequest<T extends SolrResponse> implements Serializable {
+ // This user principal is typically used by Auth plugins during distributed/sharded search
+ private Principal userPrincipal;
+
+ public void setUserPrincipal(Principal userPrincipal) {
+ this.userPrincipal = userPrincipal;
+ }
+
+ public Principal getUserPrincipal() {
+ return userPrincipal;
+ }
public enum METHOD {
GET,
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c1851096/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 2b60e33..057122e 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
@@ -24,6 +24,7 @@ import java.lang.invoke.MethodHandles;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
+import java.security.Principal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -252,7 +253,7 @@ public class HttpSolrClient extends SolrClient {
throws SolrServerException, IOException {
HttpRequestBase method = createMethod(request, collection);
setBasicAuthHeader(request, method);
- return executeMethod(method, processor, isV2ApiRequest(request));
+ return executeMethod(method, request.getUserPrincipal(), processor, isV2ApiRequest(request));
}
private boolean isV2ApiRequest(final SolrRequest request) {
@@ -296,7 +297,7 @@ public class HttpSolrClient extends SolrClient {
ExecutorService pool = ExecutorUtil.newMDCAwareFixedThreadPool(1, new SolrjNamedThreadFactory("httpUriRequest"));
try {
MDC.put("HttpSolrClient.url", baseUrl);
- mrr.future = pool.submit(() -> executeMethod(method, processor, isV2ApiRequest(request)));
+ mrr.future = pool.submit(() -> executeMethod(method, request.getUserPrincipal(), processor, isV2ApiRequest(request)));
} finally {
pool.shutdown();
@@ -517,7 +518,7 @@ public class HttpSolrClient extends SolrClient {
private static final List<String> errPath = Arrays.asList("metadata", "error-class");//Utils.getObjectByPath(err, false,"metadata/error-class")
- protected NamedList<Object> executeMethod(HttpRequestBase method, final ResponseParser processor, final boolean isV2Api) throws SolrServerException {
+ protected NamedList<Object> executeMethod(HttpRequestBase method, Principal userPrincipal, final ResponseParser processor, final boolean isV2Api) throws SolrServerException {
method.addHeader("User-Agent", AGENT);
org.apache.http.client.config.RequestConfig.Builder requestConfigBuilder = HttpClientUtil.createDefaultRequestConfigBuilder();
@@ -539,6 +540,12 @@ public class HttpSolrClient extends SolrClient {
try {
// Execute the method.
HttpClientContext httpClientRequestContext = HttpClientUtil.createNewHttpClientRequestContext();
+ if (userPrincipal != null) {
+ // Normally the context contains a static userToken to enable reuse resources.
+ // However, if a personal Principal object exists, we use that instead, also as a means
+ // to transfer authentication information to Auth plugins that wish to intercept the request later
+ httpClientRequestContext.setUserToken(userPrincipal);
+ }
final HttpResponse response = httpClient.execute(method, httpClientRequestContext);
int httpStatus = response.getStatusLine().getStatusCode();