Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 7A4AC200C3B for ; Sat, 18 Mar 2017 18:32:15 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 772D3160B7F; Sat, 18 Mar 2017 17:32:15 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 72CD1160B7A for ; Sat, 18 Mar 2017 18:32:14 +0100 (CET) Received: (qmail 76817 invoked by uid 500); 18 Mar 2017 17:32:13 -0000 Mailing-List: contact commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@lucene.apache.org Delivered-To: mailing list commits@lucene.apache.org Received: (qmail 76808 invoked by uid 99); 18 Mar 2017 17:32:13 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 18 Mar 2017 17:32:13 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 8364DDFD73; Sat, 18 Mar 2017 17:32:13 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: ishan@apache.org To: commits@lucene.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: lucene-solr:jira/solr-6736: SOLR-6736: Overhaul of authorization response and RuleBasedAuthorizationPlugin Date: Sat, 18 Mar 2017 17:32:13 +0000 (UTC) archived-at: Sat, 18 Mar 2017 17:32:15 -0000 Repository: lucene-solr Updated Branches: refs/heads/jira/solr-6736 a2931a147 -> 4d6d8238d SOLR-6736: Overhaul of authorization response and RuleBasedAuthorizationPlugin Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/4d6d8238 Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/4d6d8238 Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/4d6d8238 Branch: refs/heads/jira/solr-6736 Commit: 4d6d8238da15b9a096a3ee288f25c38e37229b41 Parents: a2931a1 Author: Ishan Chattopadhyaya Authored: Sat Mar 18 23:02:01 2017 +0530 Committer: Ishan Chattopadhyaya Committed: Sat Mar 18 23:02:01 2017 +0530 ---------------------------------------------------------------------- .../solr/handler/admin/ConfigSetsHandler.java | 44 ++++++++++++-------- .../solr/security/AuthorizationResponse.java | 19 +++++++-- .../security/RuleBasedAuthorizationPlugin.java | 44 +++++++++++--------- .../org/apache/solr/servlet/HttpSolrCall.java | 9 +++- .../solr/security/MockAuthorizationPlugin.java | 8 ++-- 5 files changed, 77 insertions(+), 47 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d6d8238/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java ---------------------------------------------------------------------- diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java index 8b76912..5d78af0 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java @@ -60,7 +60,10 @@ import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.security.AuthorizationContext; +import org.apache.solr.security.AuthorizationPlugin; +import org.apache.solr.security.AuthorizationResponse; import org.apache.solr.security.PermissionNameProvider; +import org.apache.solr.security.RuleBasedAuthorizationPlugin; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; @@ -170,23 +173,7 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN InputStream inputStream = contentStreamsIterator.next().getStream(); // Create a node for the configuration in zookeeper nocommit: do this only if /admin is not protected by authz/authc - boolean trusted = false; - /*AuthorizationPlugin authz = coreContainer.getAuthorizationPlugin(); - if (authz == null) { - trusted = false; - } else { - if (authz instanceof RuleBasedAuthorizationPlugin) { - List permissions = ((RuleBasedAuthorizationPlugin) authz).getPermissions("/admin/config"); - System.out.println("Permissions for this path: "+permissions); - if (permissions.isEmpty()) { - trusted = false; - } else { - trusted = true; - } - } else { - trusted = true; - } - }*/ + boolean trusted = getTrusted(req); zkClient.makePath(configPathInZk, ("{\"trusted\": "+Boolean.toString(trusted)+"}").getBytes(StandardCharsets.UTF_8), true); ZipInputStream zis = new ZipInputStream(inputStream, StandardCharsets.UTF_8); @@ -206,7 +193,28 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN rsp.add("message", configSetName + " successfully uploaded!"); } - private void createZkNodeIfNotExistsAndSetData(SolrZkClient zkClient, + boolean getTrusted(SolrQueryRequest req) { + AuthorizationPlugin authzPlugin = coreContainer.getAuthorizationPlugin(); + AuthorizationResponse authzResponse = req.getHttpSolrCall().getAuthorizationResponse(); + + System.out.println("Authz plugin: "+authzPlugin); + System.out.println("Authz permission: "+authzResponse.getPermission()); + if (authzPlugin != null) { + if (authzPlugin instanceof RuleBasedAuthorizationPlugin) { + if (authzResponse.getPermission() == null) { // this request was permitted since this endpoint was not protected + return false; + } else { + return true; // there was a particular permission that passed, and hence this endpoint is protected + } + } else { + return true; // trust all other authz plugins to have done the authorization properly + } + } else { + return false; + } + } + + private void createZkNodeIfNotExistsAndSetData(SolrZkClient zkClient, String filePathInZk, byte[] data) throws Exception { if (!zkClient.exists(filePathInZk, true)) { zkClient.create(filePathInZk, data, CreateMode.PERSISTENT, true); http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d6d8238/solr/core/src/java/org/apache/solr/security/AuthorizationResponse.java ---------------------------------------------------------------------- diff --git a/solr/core/src/java/org/apache/solr/security/AuthorizationResponse.java b/solr/core/src/java/org/apache/solr/security/AuthorizationResponse.java index 6c84489..5e756b0 100644 --- a/solr/core/src/java/org/apache/solr/security/AuthorizationResponse.java +++ b/solr/core/src/java/org/apache/solr/security/AuthorizationResponse.java @@ -20,14 +20,21 @@ package org.apache.solr.security; be used to return ACLs and other information from the authorization plugin. */ public class AuthorizationResponse { - public static final AuthorizationResponse OK = new AuthorizationResponse(200); - public static final AuthorizationResponse FORBIDDEN = new AuthorizationResponse(403); - public static final AuthorizationResponse PROMPT = new AuthorizationResponse(401); + public static final int OK_STATUS = 200; + public static final int FORBIDDEN_STATUS = 403; + public static final int PROMPT_STATUS = 401; + public final int statusCode; + + /** + * nocommit javadocs + */ + private final Permission permission; String message; - public AuthorizationResponse(int httpStatusCode) { + public AuthorizationResponse(int httpStatusCode, Permission permission) { this.statusCode = httpStatusCode; + this.permission = permission; } public String getMessage() { @@ -37,4 +44,8 @@ public class AuthorizationResponse { public void setMessage(String message) { this.message = message; } + + public Permission getPermission() { + return permission; + } } http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d6d8238/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java ---------------------------------------------------------------------- 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 7e3b7ab..398af16 100644 --- a/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java @@ -99,32 +99,34 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config public AuthorizationResponse authorize(AuthorizationContext context) { List collectionRequests = context.getCollectionRequests(); if (context.getRequestType() == AuthorizationContext.RequestType.ADMIN) { - MatchStatus flag = checkCollPerm(mapping.get(null), context); - return flag.rsp; + return checkCollPerm(mapping.get(null), context); } for (AuthorizationContext.CollectionRequest collreq : collectionRequests) { //check permissions for each collection - MatchStatus flag = checkCollPerm(mapping.get(collreq.collectionName), context); - if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag.rsp; + AuthorizationResponse rsp = checkCollPerm(mapping.get(collreq.collectionName), context); + if (rsp.getPermission() == null) return rsp; } //check wildcard (all=*) permissions. - MatchStatus flag = checkCollPerm(mapping.get("*"), context); - return flag.rsp; + return checkCollPerm(mapping.get("*"), context); } - private MatchStatus checkCollPerm(Map> pathVsPerms, + private AuthorizationResponse checkCollPerm(Map> pathVsPerms, AuthorizationContext context) { - if (pathVsPerms == null) return MatchStatus.NO_PERMISSIONS_FOUND; + if (pathVsPerms == null) { + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, null); + } String path = context.getResource(); - MatchStatus flag = checkPathPerm(pathVsPerms.get(path), context); - if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag; + AuthorizationResponse rsp = checkPathPerm(pathVsPerms.get(path), context); + if (rsp.getPermission() != null) return rsp; return checkPathPerm(pathVsPerms.get(null), context); } - private MatchStatus checkPathPerm(List permissions, AuthorizationContext context) { - if (permissions == null || permissions.isEmpty()) return MatchStatus.NO_PERMISSIONS_FOUND; + private AuthorizationResponse checkPathPerm(List permissions, AuthorizationContext context) { + if (permissions == null || permissions.isEmpty()) { + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, null); + } Principal principal = context.getUserPrincipal(); loopPermissions: for (int i = 0; i < permissions.size(); i++) { @@ -155,26 +157,28 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config if (permission.role == null) { //no role is assigned permission.That means everybody is allowed to access - return MatchStatus.PERMITTED; + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, permission); } if (principal == null) { log.info("request has come without principal. failed permission {} ",permission); //this resource needs a principal but the request has come without //any credential. - return MatchStatus.USER_REQUIRED; + return new AuthorizationResponse(AuthorizationResponse.PROMPT_STATUS, permission); } else if (permission.role.contains("*")) { - return MatchStatus.PERMITTED; + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, permission); } for (String role : permission.role) { Set userRoles = usersVsRoles.get(principal.getName()); - if (userRoles != null && userRoles.contains(role)) return MatchStatus.PERMITTED; + if (userRoles != null && userRoles.contains(role)) { + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, permission); //nocommit should we send the role as well? + } } log.info("This resource is configured to have a permission {}, The principal {} does not have the right role ", permission, principal); - return MatchStatus.FORBIDDEN; + return new AuthorizationResponse(AuthorizationResponse.FORBIDDEN_STATUS, permission); } log.debug("No permissions configured for the resource {} . So allowed to access", context.getResource()); - return MatchStatus.NO_PERMISSIONS_FOUND; + return new AuthorizationResponse(AuthorizationResponse.OK_STATUS, null); } @Override @@ -217,7 +221,7 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config @Override public void close() throws IOException { } - enum MatchStatus { + /*enum MatchStatus { USER_REQUIRED(AuthorizationResponse.PROMPT), NO_PERMISSIONS_FOUND(AuthorizationResponse.OK), PERMITTED(AuthorizationResponse.OK), @@ -228,7 +232,7 @@ public class RuleBasedAuthorizationPlugin implements AuthorizationPlugin, Config MatchStatus(AuthorizationResponse rsp) { this.rsp = rsp; } - } + }*/ http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d6d8238/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java ---------------------------------------------------------------------- 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 3f69c15..0a54f40 100644 --- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java +++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java @@ -461,6 +461,12 @@ public class HttpSolrCall { } } + private AuthorizationResponse authorizationResponse = null; + + public AuthorizationResponse getAuthorizationResponse() { + return authorizationResponse; + } + /** * This method processes the request. */ @@ -488,7 +494,8 @@ public class HttpSolrCall { AuthorizationContext context = getAuthorizationContext(); log.debug("AuthorizationContext : {}", context); AuthorizationResponse authResponse = cores.getAuthorizationPlugin().authorize(context); - if (authResponse.statusCode == AuthorizationResponse.PROMPT.statusCode) { + this.authorizationResponse = authResponse; // downstream processing might need this + if (authResponse.statusCode == AuthorizationResponse.PROMPT_STATUS) { Map headers = (Map) getReq().getAttribute(AuthenticationPlugin.class.getName()); if (headers != null) { for (Map.Entry e : headers.entrySet()) response.setHeader(e.getKey(), e.getValue()); http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4d6d8238/solr/core/src/test/org/apache/solr/security/MockAuthorizationPlugin.java ---------------------------------------------------------------------- diff --git a/solr/core/src/test/org/apache/solr/security/MockAuthorizationPlugin.java b/solr/core/src/test/org/apache/solr/security/MockAuthorizationPlugin.java index 1cbe849..8d8d99a 100644 --- a/solr/core/src/test/org/apache/solr/security/MockAuthorizationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/MockAuthorizationPlugin.java @@ -38,9 +38,9 @@ public class MockAuthorizationPlugin implements AuthorizationPlugin { if (predicate != null) { try { predicate.test(context); - return new AuthorizationResponse(200); + return new AuthorizationResponse(200, null); } catch (SolrException e) { - return new AuthorizationResponse(e.code()); + return new AuthorizationResponse(e.code(), null); } } @@ -48,9 +48,9 @@ public class MockAuthorizationPlugin implements AuthorizationPlugin { if (uname == null) uname = context.getParams().get("uname"); log.info("User request: " + uname); if (denyUsers.contains(uname)) - return new AuthorizationResponse(403); + return new AuthorizationResponse(403, null); else - return new AuthorizationResponse(200); + return new AuthorizationResponse(200, null); } @Override