You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by is...@apache.org on 2019/07/11 00:45:20 UTC
[lucene-solr] branch jira/solr-13619 created (now cc0c644)
This is an automated email from the ASF dual-hosted git repository.
ishan pushed a change to branch jira/solr-13619
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git.
at cc0c644 SOLR-13619: Forwarded requests with Kerberos should carry forward the original user principal
This branch includes the following new commits:
new cc0c644 SOLR-13619: Forwarded requests with Kerberos should carry forward the original user principal
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[lucene-solr] 01/01: SOLR-13619: Forwarded requests with Kerberos
should carry forward the original user principal
Posted by is...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
ishan pushed a commit to branch jira/solr-13619
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
commit cc0c64457c874d05e6b45eca220a72d59c65afeb
Author: Ishan Chattopadhyaya <is...@apache.org>
AuthorDate: Thu Jul 11 06:14:55 2019 +0530
SOLR-13619: Forwarded requests with Kerberos should carry forward the original user principal
---
.../org/apache/solr/request/SolrRequestInfo.java | 22 ++++++++++-
.../org/apache/solr/security/KerberosPlugin.java | 19 +++++++++
.../security/RuleBasedAuthorizationPlugin.java | 46 +++++++++++++++++++++-
.../java/org/apache/solr/servlet/HttpSolrCall.java | 8 +++-
4 files changed, 91 insertions(+), 4 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java b/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
index 5995f2b..fb658da 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrRequestInfo.java
@@ -31,6 +31,7 @@ import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.servlet.SolrDispatchFilter;
import org.apache.solr.util.TimeZoneUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +47,7 @@ public class SolrRequestInfo {
protected TimeZone tz;
protected ResponseBuilder rb;
protected List<Closeable> closeHooks;
+ protected SolrDispatchFilter.Action action;
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -86,11 +88,21 @@ public class SolrRequestInfo {
this.req = req;
this.rsp = rsp;
}
- public SolrRequestInfo(HttpServletRequest httpReq, SolrQueryResponse rsp) {
+ public SolrRequestInfo(SolrQueryRequest req, SolrQueryResponse rsp, SolrDispatchFilter.Action action) {
+ this(req, rsp);
+ this.setAction(action);
+ }
+
+ public SolrRequestInfo(HttpServletRequest httpReq, SolrQueryResponse rsp) {
this.httpRequest = httpReq;
this.rsp = rsp;
}
+ public SolrRequestInfo(HttpServletRequest httpReq, SolrQueryResponse rsp, SolrDispatchFilter.Action action) {
+ this(httpReq, rsp);
+ this.action = action;
+ }
+
public Principal getUserPrincipal() {
if (req != null) return req.getUserPrincipal();
if (httpRequest != null) return httpRequest.getUserPrincipal();
@@ -149,6 +161,14 @@ public class SolrRequestInfo {
}
}
+ public SolrDispatchFilter.Action getAction() {
+ return action;
+ }
+
+ public void setAction(SolrDispatchFilter.Action action) {
+ this.action = action;
+ }
+
public static ExecutorUtil.InheritableThreadLocalProvider getInheritableThreadLocalProvider() {
return new ExecutorUtil.InheritableThreadLocalProvider() {
@Override
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 8bc5625..870b25e 100644
--- a/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/KerberosPlugin.java
@@ -33,6 +33,8 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationHandler;
+import org.apache.http.HttpRequest;
+import org.apache.http.protocol.HttpContext;
import org.apache.solr.client.solrj.impl.Http2SolrClient;
import org.apache.solr.client.solrj.impl.Krb5HttpClientBuilder;
import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder;
@@ -41,6 +43,9 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.SecurityAwareZkACLProvider;
import org.apache.solr.core.CoreContainer;
+import org.apache.solr.request.SolrRequestInfo;
+import org.apache.solr.servlet.HttpSolrCall;
+import org.apache.solr.servlet.SolrDispatchFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -236,6 +241,20 @@ public class KerberosPlugin extends AuthenticationPlugin implements HttpClientBu
}
@Override
+ protected boolean interceptInternodeRequest(HttpRequest httpRequest, HttpContext httpContext) {
+ SolrRequestInfo info = SolrRequestInfo.getRequestInfo();
+ if (info != null && (info.getAction() == SolrDispatchFilter.Action.FORWARD ||
+ info.getAction() == SolrDispatchFilter.Action.REMOTEQUERY)) {
+ if (info.getUserPrincipal() != null) {
+ log.info("Setting original user principal: {}", info.getUserPrincipal().getName());
+ httpRequest.setHeader(HttpSolrCall.ORIGINAL_USER_PRINCIPAL_HEADER, info.getUserPrincipal().getName());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
public SolrHttpClientBuilder getHttpClientBuilder(SolrHttpClientBuilder builder) {
return kerberosBuilder.getBuilder(builder);
}
diff --git a/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java b/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
index 8b4a65c..850517d 100644
--- a/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
@@ -30,6 +30,7 @@ import java.util.function.Function;
import org.apache.solr.common.SpecProvider;
import org.apache.solr.common.util.Utils;
import org.apache.solr.common.util.ValidatingJsonMap;
+import org.apache.solr.servlet.HttpSolrCall;
import org.apache.solr.common.util.CommandOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -111,7 +112,7 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config
private MatchStatus checkPathPerm(List<Permission> permissions, AuthorizationContext context) {
if (permissions == null || permissions.isEmpty()) return MatchStatus.NO_PERMISSIONS_FOUND;
- Principal principal = context.getUserPrincipal();
+ Principal principal = getUserPrincipal(context);
final Permission governingPermission = findFirstGoverningPermission(permissions, context);
if (governingPermission == null) {
@@ -122,6 +123,49 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config
return determineIfPermissionPermitsPrincipal(principal, governingPermission);
}
+ private Principal getUserPrincipal(AuthorizationContext context) {
+ Principal principal = context.getUserPrincipal();
+
+ // If principal is an admin user, i.e. has ALL permissions (e.g. request coming from Solr
+ // node), and "originalUserPrincipal" is specified, then set originalUserPrincipal
+ // as the principal. This is typically the case in forwarded/remote requests
+ // through KerberosPlugin. This is needed because the original node that received
+ // this request did not perform any authorization, and hence we are the first ones
+ // to authorize the request (and we need the original user principal to do so).
+ if (context.getHttpHeader("originalUserPrincipal") != null) {
+ Set<String> roles = usersVsRoles.get(principal.getName());
+ if (roles != null) {
+ for (String role: roles) {
+ if (mapping.get(null) == null) continue;
+ List<Permission> permissions = mapping.get(null).get(null);
+ if (permissions != null) {
+ for (Permission p: permissions) {
+ if (PermissionNameProvider.Name.ALL.equals(p.wellknownName) && p.role.contains(role)) {
+ // The role for the principal has ALL permissions
+ String originalUserRequest = context.getHttpHeader(HttpSolrCall.ORIGINAL_USER_PRINCIPAL_HEADER);
+ log.info("Principal: " + principal + ", original user principal: " + originalUserRequest);
+ principal = new Principal() {
+ @Override
+ public String getName() {
+ return originalUserRequest;
+ }
+
+ @Override
+ public String toString() {
+ return originalUserRequest;
+ }
+ };
+ return principal;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return principal;
+ }
+
private Permission findFirstGoverningPermission(List<Permission> permissions, AuthorizationContext context) {
for (int i = 0; i < permissions.size(); i++) {
Permission permission = permissions.get(i);
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 2ed00f4..546a195 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -137,6 +137,8 @@ import static org.apache.solr.servlet.SolrDispatchFilter.Action.RETURN;
public class HttpSolrCall {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ public static final String ORIGINAL_USER_PRINCIPAL_HEADER = "originalUserPrincipal";
+
public static final Random random;
static {
// We try to make things reproducible in the context of our tests by initializing the random instance
@@ -414,10 +416,12 @@ public class HttpSolrCall {
if (path.equals(req.getServletPath())) {
// avoid endless loop - pass through to Restlet via webapp
action = PASSTHROUGH;
+ SolrRequestInfo.getRequestInfo().setAction(action);
return;
} else {
// forward rewritten URI (without path prefix and core/collection name) to Restlet
action = FORWARD;
+ SolrRequestInfo.getRequestInfo().setAction(action);
return;
}
}
@@ -542,7 +546,7 @@ public class HttpSolrCall {
handleAdminRequest();
return RETURN;
case REMOTEQUERY:
- SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, new SolrQueryResponse()));
+ SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, new SolrQueryResponse(), action));
remoteQuery(coreUrl + path, resp);
return RETURN;
case PROCESS:
@@ -558,7 +562,7 @@ public class HttpSolrCall {
* QueryResponseWriter is selected and we get the correct
* Content-Type)
*/
- SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp));
+ SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp, action));
execute(solrRsp);
if (shouldAudit()) {
EventType eventType = solrRsp.getException() == null ? EventType.COMPLETED : EventType.ERROR;