This is an automated email from the ASF dual-hosted git repository.

abhay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new bc596e627 RANGER-4820: Support authorization of multiple accesses 
grouped by access groups in one policy engine call - #2
bc596e627 is described below

commit bc596e627f394d6d8a683fc7a8e09260ebecc3ac
Author: Abhay Kulkarni <[email protected]>
AuthorDate: Fri Sep 13 15:18:49 2024 -0700

    RANGER-4820: Support authorization of multiple accesses grouped by access 
groups in one policy engine call - #2
---
 .../RangerDefaultPolicyEvaluator.java              |  39 +++++--
 .../plugin/util/RangerAccessRequestUtil.java       | 124 +++++++++++++--------
 .../authorization/hadoop/RangerHdfsAuthorizer.java |   6 +
 3 files changed, 108 insertions(+), 61 deletions(-)

diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
index be6cd5584..621b65137 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
@@ -887,7 +887,7 @@ public class RangerDefaultPolicyEvaluator extends 
RangerAbstractPolicyEvaluator
                                }
                        }
 
-                       RangerAccessResult compositeAccessResult = 
getCompositeAccessResult(request);
+                       RangerAccessResult compositeAccessResult = 
getCompositeAccessResult(request, result);
                        if (compositeAccessResult != null) {
                                
result.setAccessResultFrom(compositeAccessResult);
                        }
@@ -937,39 +937,54 @@ public class RangerDefaultPolicyEvaluator extends 
RangerAbstractPolicyEvaluator
                return ret;
        }
 
-       private RangerAccessResult getCompositeAccessResult(RangerAccessRequest 
request) {
-               RangerAccessResult      ret                             = null;
-               Set<Set<String>>        allAccessTypeGroups = 
RangerAccessRequestUtil.getAllRequestedAccessTypeGroups(request);
-               Set<String>             allAccessTypes      = 
RangerAccessRequestUtil.getAllRequestedAccessTypes(request);
+       private RangerAccessResult getCompositeAccessResult(RangerAccessRequest 
request, RangerAccessResult result) {
+               RangerAccessResult ret                          = null;
+               Set<Set<String>>   allAccessTypeGroups          = 
RangerAccessRequestUtil.getAllRequestedAccessTypeGroups(request);
+               Set<String>        allAccessTypes               = 
RangerAccessRequestUtil.getAllRequestedAccessTypes(request);
+               Set<String>        ignoreIfNotDeniedAccessTypes = 
RangerAccessRequestUtil.getIgnoreIfNotDeniedAccessTypes(request);
 
                if (CollectionUtils.isEmpty(allAccessTypeGroups)) {
                        ret = deriveAccessResultFromGroup(request, 
allAccessTypes);
+                       if (ret == null && 
CollectionUtils.isNotEmpty(ignoreIfNotDeniedAccessTypes) && 
ignoreIfNotDeniedAccessTypes.containsAll(allAccessTypes)) {
+                               // group does not allow/deny access and this 
group's all access-types are also in the ignore-if-not-denied access-type list
+                               ret = new 
RangerAccessResult(result.getPolicyType(), result.getServiceName(), 
result.getServiceDef(), request);
+                               ret.setAuditResultFrom(result);
+                               ret.setIsAllowed(true);
+                       }
                } else {
-                       boolean                         isAccessDetermined      
= true;
-                       boolean                         isAccessAllowed         
= false;
-                       RangerAccessResult      allowResult                     
= null;
+                       boolean            isAccessDetermined = true;
+                       boolean            isAccessAllowed    = false;
+                       RangerAccessResult allowResult        = null;
 
                        for (Set<String> accessesInGroup : allAccessTypeGroups) 
{
                                RangerAccessResult groupResult = 
deriveAccessResultFromGroup(request, accessesInGroup);
                                if (groupResult != null) {
                                        if (!groupResult.getIsAllowed()) {
                                                // Deny
-                                               isAccessAllowed = false;
-                                               ret                             
= groupResult;
+                                               isAccessAllowed = false;
+                                               ret             = groupResult;
                                                break;
                                        } else {
-                                               isAccessAllowed = true;
+                                               isAccessAllowed = true;
                                                if (allowResult == null) {
                                                        allowResult = 
groupResult;
                                                }
                                        }
                                } else {
                                        // Some group is not completely 
authorized yet
-                                       isAccessDetermined = false;
+                                       if 
(!(CollectionUtils.isNotEmpty(ignoreIfNotDeniedAccessTypes) && 
ignoreIfNotDeniedAccessTypes.containsAll(accessesInGroup))) {
+                                               // group does not allow/deny 
access and this group's all access-types are also in the ignore-if-not-denied 
access-type list
+                                               isAccessDetermined = false;
+                                       }
                                }
                        }
+
                        if (isAccessDetermined && isAccessAllowed) {
                                ret = allowResult;
+                       } else if (isAccessDetermined && ret == null) { // If 
none of the groups allowed/denied access and every group's all access-type 
results are to be ignored unless denied
+                               ret = new 
RangerAccessResult(result.getPolicyType(), result.getServiceName(), 
result.getServiceDef(), request);
+                               ret.setAuditResultFrom(result);
+                               ret.setIsAllowed(true);
                        }
                }
                return ret;
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
index de31737d6..6546e287c 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
@@ -34,29 +34,30 @@ import org.slf4j.LoggerFactory;
 public class RangerAccessRequestUtil {
        private static final Logger LOG = 
LoggerFactory.getLogger(RangerAccessRequestUtil.class);
 
-       public static final String KEY_CONTEXT_TAGS                             
        = "TAGS";
-       public static final String KEY_CONTEXT_TAG_OBJECT                       
= "TAG_OBJECT";
-       public static final String KEY_CONTEXT_RESOURCE                         
= "RESOURCE";
-       public static final String KEY_CONTEXT_REQUESTED_RESOURCES      = 
"REQUESTED_RESOURCES";
-       public static final String KEY_CONTEXT_USERSTORE                        
= "USERSTORE";
-       public static final String KEY_TOKEN_NAMESPACE                          
= "token:";
-       public static final String KEY_USER                                     
        = "USER";
-       public static final String KEY_OWNER                                    
        = "OWNER";
-       public static final String KEY_ROLES                                    
        = "ROLES";
-       public static final String KEY_CONTEXT_IS_ANY_ACCESS            = 
"ISANYACCESS";
-       public static final String KEY_CONTEXT_ALL_ACCESSTYPE_GROUPS = 
"ALLACCESSTYPEGROUPS";
-       public static final String KEY_CONTEXT_ALL_ACCESSTYPES          = 
"ALLACCESSTYPES";
-       public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS  = 
"ALL_ACCESS_TYPE_RESULTS";
-       public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS      
= "ALL_ACCESS_TYPE_ACL_RESULTS";
-
-       public static final String KEY_CONTEXT_REQUEST                          
= "_REQUEST";
-       public static final String KEY_CONTEXT_GDS_RESULT    = "_GDS_RESULT";
-       public static final String KEY_CONTEXT_IS_REQUEST_PREPROCESSED  = 
"ISREQUESTPREPROCESSED";
-       public static final String KEY_CONTEXT_RESOURCE_ZONE_NAMES              
= "RESOURCE_ZONE_NAMES";
-       public static final String KEY_CONTEXT_IS_SKIP_CHAINED_PLUGINS  = 
"_IS_SKIP_CHAINED_PLUGINS";
+       public static final String KEY_CONTEXT_TAGS                             
= "TAGS";
+       public static final String KEY_CONTEXT_TAG_OBJECT                       
= "TAG_OBJECT";
+       public static final String KEY_CONTEXT_RESOURCE                         
= "RESOURCE";
+       public static final String KEY_CONTEXT_REQUESTED_RESOURCES              
= "REQUESTED_RESOURCES";
+       public static final String KEY_CONTEXT_USERSTORE                        
= "USERSTORE";
+       public static final String KEY_TOKEN_NAMESPACE                          
= "token:";
+       public static final String KEY_USER                                     
= "USER";
+       public static final String KEY_OWNER                                    
= "OWNER";
+       public static final String KEY_ROLES                                    
= "ROLES";
+       public static final String KEY_CONTEXT_IS_ANY_ACCESS                    
= "ISANYACCESS";
+       public static final String KEY_CONTEXT_ALL_ACCESSTYPE_GROUPS            
= "ALLACCESSTYPEGROUPS";
+       public static final String KEY_CONTEXT_ALL_ACCESSTYPES                  
= "ALLACCESSTYPES";
+       public static final String KEY_CONTEXT_IGNORE_IF_NOT_DENIED_ACCESSTYPES 
= "IGNOREIFNOTDENIEDACCESSTYPES";
+       public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS          
= "ALL_ACCESS_TYPE_RESULTS";
+       public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS      
= "ALL_ACCESS_TYPE_ACL_RESULTS";
+
+       public static final String KEY_CONTEXT_REQUEST                 = 
"_REQUEST";
+       public static final String KEY_CONTEXT_GDS_RESULT              = 
"_GDS_RESULT";
+       public static final String KEY_CONTEXT_IS_REQUEST_PREPROCESSED = 
"ISREQUESTPREPROCESSED";
+       public static final String KEY_CONTEXT_RESOURCE_ZONE_NAMES     = 
"RESOURCE_ZONE_NAMES";
+       public static final String KEY_CONTEXT_IS_SKIP_CHAINED_PLUGINS = 
"_IS_SKIP_CHAINED_PLUGINS";
 
        public static void setRequestTagsInContext(Map<String, Object> context, 
Set<RangerTagForEval> tags) {
-               if(CollectionUtils.isEmpty(tags)) {
+               if (CollectionUtils.isEmpty(tags)) {
                        context.remove(KEY_CONTEXT_TAGS);
                } else {
                        context.put(KEY_CONTEXT_TAGS, tags);
@@ -65,12 +66,11 @@ public class RangerAccessRequestUtil {
 
        public static Set<RangerTagForEval> 
getRequestTagsFromContext(Map<String, Object> context) {
                Set<RangerTagForEval> ret = null;
-               Object          val = 
context.get(RangerAccessRequestUtil.KEY_CONTEXT_TAGS);
+               Object                val = 
context.get(RangerAccessRequestUtil.KEY_CONTEXT_TAGS);
 
                if (val instanceof Set<?>) {
                        try {
-                               @SuppressWarnings("unchecked")
-                               Set<RangerTagForEval> tags = 
(Set<RangerTagForEval>) val;
+                               @SuppressWarnings("unchecked") 
Set<RangerTagForEval> tags = (Set<RangerTagForEval>) val;
 
                                ret = tags;
                        } catch (Throwable t) {
@@ -87,10 +87,10 @@ public class RangerAccessRequestUtil {
 
        public static RangerTagForEval getCurrentTagFromContext(Map<String, 
Object> context) {
                RangerTagForEval ret = null;
-               Object    val = context.get(KEY_CONTEXT_TAG_OBJECT);
+               Object           val = context.get(KEY_CONTEXT_TAG_OBJECT);
 
-               if(val instanceof RangerTagForEval) {
-                       ret = (RangerTagForEval)val;
+               if (val instanceof RangerTagForEval) {
+                       ret = (RangerTagForEval) val;
                }
 
                return ret;
@@ -104,8 +104,8 @@ public class RangerAccessRequestUtil {
                RangerRequestedResources ret = null;
                Object                   val = 
context.get(KEY_CONTEXT_REQUESTED_RESOURCES);
 
-               if(val instanceof RangerRequestedResources) {
-                       ret = (RangerRequestedResources)val;
+               if (val instanceof RangerRequestedResources) {
+                       ret = (RangerRequestedResources) val;
                }
 
                return ret;
@@ -119,8 +119,8 @@ public class RangerAccessRequestUtil {
                RangerAccessResource ret = null;
                Object               val = MapUtils.isNotEmpty(context) ? 
context.get(KEY_CONTEXT_RESOURCE) : null;
 
-               if(val instanceof RangerAccessResource) {
-                       ret = (RangerAccessResource)val;
+               if (val instanceof RangerAccessResource) {
+                       ret = (RangerAccessResource) val;
                }
 
                return ret;
@@ -129,7 +129,7 @@ public class RangerAccessRequestUtil {
        public static Map<String, Object> copyContext(Map<String, Object> 
context) {
                final Map<String, Object> ret;
 
-               if(MapUtils.isEmpty(context)) {
+               if (MapUtils.isEmpty(context)) {
                        ret = new HashMap<>();
                } else {
                        ret = new HashMap<>(context);
@@ -145,6 +145,7 @@ public class RangerAccessRequestUtil {
                        ret.remove(KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS);
                        ret.remove(KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS);
                        ret.remove(KEY_CONTEXT_IS_REQUEST_PREPROCESSED);
+                       
ret.remove(KEY_CONTEXT_IGNORE_IF_NOT_DENIED_ACCESSTYPES);
                        // don't remove REQUESTED_RESOURCES
                }
 
@@ -154,9 +155,11 @@ public class RangerAccessRequestUtil {
        public static void setCurrentUserInContext(Map<String, Object> context, 
String user) {
                setTokenInContext(context, KEY_USER, user);
        }
+
        public static void setOwnerInContext(Map<String, Object> context, 
String owner) {
                setTokenInContext(context, KEY_OWNER, owner);
        }
+
        public static String getCurrentUserFromContext(Map<String, Object> 
context) {
                Object ret = getTokenFromContext(context, KEY_USER);
                return ret != null ? ret.toString() : "";
@@ -166,21 +169,22 @@ public class RangerAccessRequestUtil {
                String tokenNameWithNamespace = KEY_TOKEN_NAMESPACE + tokenName;
                context.put(tokenNameWithNamespace, tokenValue);
        }
+
        public static Object getTokenFromContext(Map<String, Object> context, 
String tokenName) {
                String tokenNameWithNamespace = KEY_TOKEN_NAMESPACE + tokenName;
                return MapUtils.isNotEmpty(context) ? 
context.get(tokenNameWithNamespace) : null;
        }
 
-    public static void setCurrentUserRolesInContext(Map<String, Object> 
context, Set<String> roles) {
-        setTokenInContext(context, KEY_ROLES, roles);
-    }
+       public static void setCurrentUserRolesInContext(Map<String, Object> 
context, Set<String> roles) {
+               setTokenInContext(context, KEY_ROLES, roles);
+       }
 
-    public static Set<String> getCurrentUserRolesFromContext(Map<String, 
Object> context) {
-        Object ret = getTokenFromContext(context, KEY_ROLES);
-        return ret != null ? (Set<String>) ret : Collections.EMPTY_SET;
-    }
+       public static Set<String> getCurrentUserRolesFromContext(Map<String, 
Object> context) {
+               Object ret = getTokenFromContext(context, KEY_ROLES);
+               return ret != null ? (Set<String>) ret : Collections.EMPTY_SET;
+       }
 
-    public static Set<String> getUserRoles(RangerAccessRequest request) {
+       public static Set<String> getUserRoles(RangerAccessRequest request) {
                Set<String> ret = Collections.EMPTY_SET;
 
                if (request != null) {
@@ -200,9 +204,9 @@ public class RangerAccessRequestUtil {
 
        public static RangerUserStore 
getRequestUserStoreFromContext(Map<String, Object> context) {
                RangerUserStore ret = null;
-               Object    val = context.get(KEY_CONTEXT_USERSTORE);
+               Object          val = context.get(KEY_CONTEXT_USERSTORE);
 
-               if(val instanceof RangerUserStore) {
+               if (val instanceof RangerUserStore) {
                        ret = (RangerUserStore) val;
                }
 
@@ -214,7 +218,7 @@ public class RangerAccessRequestUtil {
        }
 
        public static boolean getIsAnyAccessInContext(Map<String, Object> 
context) {
-               Boolean value = (Boolean)context.get(KEY_CONTEXT_IS_ANY_ACCESS);
+               Boolean value = (Boolean) 
context.get(KEY_CONTEXT_IS_ANY_ACCESS);
                return value != null && value;
        }
 
@@ -223,7 +227,7 @@ public class RangerAccessRequestUtil {
        }
 
        public static boolean getIsRequestPreprocessed(Map<String, Object> 
context) {
-               Boolean value = 
(Boolean)context.get(KEY_CONTEXT_IS_REQUEST_PREPROCESSED);
+               Boolean value = (Boolean) 
context.get(KEY_CONTEXT_IS_REQUEST_PREPROCESSED);
                return value != null && value;
        }
 
@@ -231,6 +235,28 @@ public class RangerAccessRequestUtil {
                context.put(KEY_CONTEXT_ALL_ACCESSTYPES, accessTypes);
        }
 
+       public static void setIgnoreIfNotDeniedAccessTypes(Map<String, Object> 
context, Set<String> accessTypes) {
+               context.put(KEY_CONTEXT_IGNORE_IF_NOT_DENIED_ACCESSTYPES, 
accessTypes);
+       }
+
+       public static Set<String> 
getIgnoreIfNotDeniedAccessTypes(RangerAccessRequest request) {
+               Set<String> ret = Collections.emptySet();
+
+               Object val = 
request.getContext().get(KEY_CONTEXT_IGNORE_IF_NOT_DENIED_ACCESSTYPES);
+
+               if (val != null) {
+                       if (val instanceof Set<?>) {
+                               ret = (Set<String>) val;
+                       } else if (val instanceof List<?>) {
+                               ret = new TreeSet<>((List<String>) val);
+                       } else {
+                               LOG.error("getNotDeniedRequestedAccessTypes(): 
failed to get NOTDENIEDACCESSTYPES from context");
+                       }
+               }
+               return ret;
+       }
+
+
        @SuppressWarnings("unchecked")
        public static Set<String> 
getAllRequestedAccessTypes(RangerAccessRequest request) {
                Set<String> ret = null;
@@ -251,7 +277,7 @@ public class RangerAccessRequestUtil {
        }
 
        public static Set<Set<String>> 
getAllRequestedAccessTypeGroups(RangerAccessRequest request) {
-               Object      val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESSTYPE_GROUPS);
+               Object val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESSTYPE_GROUPS);
                return (Set<Set<String>>) val;
        }
 
@@ -265,7 +291,7 @@ public class RangerAccessRequestUtil {
 
        public static Map<String, RangerAccessResult> 
getAccessTypeResults(RangerAccessRequest request) {
                Map<String, RangerAccessResult> ret;
-               Object      val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS);
+               Object                          val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS);
                if (val == null) {
                        ret = new HashMap<>();
                        
request.getContext().put(KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS, ret);
@@ -277,7 +303,7 @@ public class RangerAccessRequestUtil {
 
        public static Map<String, Integer> 
getAccessTypeACLResults(RangerAccessRequest request) {
                Map<String, Integer> ret;
-               Object      val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS);
+               Object               val = 
request.getContext().get(KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS);
                if (val == null) {
                        ret = new HashMap<>();
                        
request.getContext().put(KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS, ret);
@@ -400,7 +426,7 @@ public class RangerAccessRequestUtil {
                if (context != null) {
                        Object o = 
context.get(KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS);
                        if (o != null) {
-                               ret = (Map<String, RangerAccessResult>)o;
+                               ret = (Map<String, RangerAccessResult>) o;
                        }
                }
 
@@ -426,7 +452,7 @@ public class RangerAccessRequestUtil {
        }
 
        public static boolean getIsSkipChainedPlugins(Map<String, Object> 
context) {
-               Boolean value = 
(Boolean)context.get(KEY_CONTEXT_IS_SKIP_CHAINED_PLUGINS);
+               Boolean value = (Boolean) 
context.get(KEY_CONTEXT_IS_SKIP_CHAINED_PLUGINS);
                return value != null && value;
        }
 }
diff --git 
a/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizer.java
 
b/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizer.java
index aa59e3ad6..9ce25695c 100644
--- 
a/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizer.java
+++ 
b/hdfs-agent/src/main/java/org/apache/ranger/authorization/hadoop/RangerHdfsAuthorizer.java
@@ -899,6 +899,9 @@ public class RangerHdfsAuthorizer extends 
INodeAttributeProvider {
 
                                        
RangerAccessRequestUtil.setAllRequestedAccessTypeGroups(request, 
allAccessTypeGroups);
                                        
RangerAccessRequestUtil.setAllRequestedAccessTypes(request.getContext(), 
accessTypes);
+                                       if 
(accessTypes.contains(EXECUTE_ACCCESS_TYPE)) {
+                                               
RangerAccessRequestUtil.setIgnoreIfNotDeniedAccessTypes(request.getContext(), 
access2ActionListMapper.get(FsAction.EXECUTE));
+                                       }
                                }
 
                                // if the request was already allowed by a 
Ranger policy (for ancestor/parent/node/child), skip chained plugin evaluations 
in subsequent calls
@@ -979,6 +982,9 @@ public class RangerHdfsAuthorizer extends 
INodeAttributeProvider {
 
                                                
RangerAccessRequestUtil.setAllRequestedAccessTypeGroups(request, 
allAccessTypeGroups);
                                                
RangerAccessRequestUtil.setAllRequestedAccessTypes(request.getContext(), 
accessTypes);
+                                               if 
(accessTypes.contains(EXECUTE_ACCCESS_TYPE)) {
+                                                       
RangerAccessRequestUtil.setIgnoreIfNotDeniedAccessTypes(request.getContext(), 
access2ActionListMapper.get(FsAction.EXECUTE));
+                                               }
                                        }
 
                                        RangerAccessResult result = 
context.plugin.isAccessAllowed(request, null);

Reply via email to