This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch ranger-2.6 in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 8904dfc06a505edfbe1c3ad97fa094083c1feb99 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 (cherry picked from commit bc596e627f394d6d8a683fc7a8e09260ebecc3ac) --- .../RangerDefaultPolicyEvaluator.java | 39 ++++--- .../plugin/util/RangerAccessRequestUtil.java | 120 +++++++++++++-------- .../authorization/hadoop/RangerHdfsAuthorizer.java | 6 ++ 3 files changed, 106 insertions(+), 59 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 f39a3b9e3..7f20f3fa4 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 @@ -33,28 +33,29 @@ 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_ACCESSTYPES = "ALLACCESSTYPES"; - public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_RESULTS = "ALL_ACCESS_TYPE_RESULTS"; - public static final String KEY_CONTEXT_REQUEST = "_REQUEST"; - 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_ALL_ACCESSTYPE_GROUPS = "ALLACCESSTYPEGROUPS"; - public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS = "ALL_ACCESS_TYPE_ACL_RESULTS"; + 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_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_REQUEST = "_REQUEST"; + 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_ALL_ACCESSTYPE_GROUPS = "ALLACCESSTYPEGROUPS"; + public static final String KEY_CONTEXT_ALL_ACCESS_TYPE_ACL_RESULTS = "ALL_ACCESS_TYPE_ACL_RESULTS"; 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); @@ -63,12 +64,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) { @@ -85,10 +85,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; @@ -102,8 +102,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; @@ -117,8 +117,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; @@ -127,7 +127,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); @@ -142,6 +142,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 } @@ -151,9 +152,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() : ""; @@ -163,21 +166,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) { @@ -197,9 +201,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; } @@ -211,7 +215,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; } @@ -220,7 +224,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; } @@ -228,6 +232,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; @@ -248,7 +274,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; } @@ -262,7 +288,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); @@ -274,7 +300,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); @@ -371,7 +397,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; } } @@ -397,7 +423,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 fa4a90c65..02cbaea64 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 @@ -900,6 +900,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 @@ -980,6 +983,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);
