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 2017/03/18 17:32:13 UTC

lucene-solr:jira/solr-6736: SOLR-6736: Overhaul of authorization response and RuleBasedAuthorizationPlugin

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 <is...@apache.org>
Authored: Sat Mar 18 23:02:01 2017 +0530
Committer: Ishan Chattopadhyaya <is...@apache.org>
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<Permission> 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<AuthorizationContext.CollectionRequest> 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<String, List<Permission>> pathVsPerms,
+  private AuthorizationResponse checkCollPerm(Map<String, List<Permission>> 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<Permission> permissions, AuthorizationContext context) {
-    if (permissions == null || permissions.isEmpty()) return MatchStatus.NO_PERMISSIONS_FOUND;
+  private AuthorizationResponse checkPathPerm(List<Permission> 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<String> 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<String, String> headers = (Map) getReq().getAttribute(AuthenticationPlugin.class.getName());
           if (headers != null) {
             for (Map.Entry<String, String> 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