You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ab...@apache.org on 2024/09/24 17:03:53 UTC

(ranger) branch master updated: RANGER-4820: Support authorization of multiple accesses grouped by access groups in one policy engine call - #2

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 <ak...@cloudera.com>
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);