From eb67dfbdfe7d784d89374076e036f01576c20867 Mon Sep 17 00:00:00 2001 From: Ramesh Mani Date: Tue, 26 May 2026 09:41:06 -0700 Subject: [PATCH] RANGER-5610:getResourceACLs for a principal should consider validitySchedule of principal for ACL creation --- .../RangerAbstractPolicyEvaluator.java | 128 ++++++++++++++++++ .../gds/gds_info_hive_access.json | 13 ++ .../gds/test_gds_policy_hive_access.json | 23 ++++ 3 files changed, 164 insertions(+) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java index 7c45f6dfbea..a55f8535f7f 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java @@ -20,8 +20,12 @@ package org.apache.ranger.plugin.policyevaluator; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.plugin.conditionevaluator.RangerValidityScheduleConditionEvaluator; import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemRowFilterInfo; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; @@ -32,6 +36,7 @@ import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceMatchingScope; import org.apache.ranger.plugin.policyengine.RangerPluginContext; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.policyengine.RangerResourceACLs.DataMaskResult; @@ -199,6 +204,7 @@ public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls if (policyType == RangerPolicy.POLICY_TYPE_ACCESS) { updateFromPolicyACLs(isConditionalMatch, acls, targetAccessTypes); + filterAclResultsByValiditySchedule(request, acls); } else if (policyType == RangerPolicy.POLICY_TYPE_ROWFILTER) { updateRowFiltersFromPolicy(isConditionalMatch, acls, targetAccessTypes); } else if (policyType == RangerPolicy.POLICY_TYPE_DATAMASK) { @@ -412,6 +418,128 @@ private void updateFromPolicyACLs(boolean isConditional, RangerResourceACLs reso } } + private void filterAclResultsByValiditySchedule(RangerAccessRequest request, RangerResourceACLs resourceACLs) { + if (request == null || resourceACLs == null || request.getAccessTime() == null) { + return; + } + + String user = request.getUser(); + Set groups = request.getUserGroups(); + Set roles = request.getUserRoles(); + + if (StringUtils.isBlank(user) && CollectionUtils.isEmpty(groups) && CollectionUtils.isEmpty(roles)) { + return; + } + + RangerPolicy policy = getPolicy(); + if (policy == null) { + return; + } + + List policyItems = new ArrayList<>(); + policyItems.addAll(policy.getPolicyItems()); + policyItems.addAll(policy.getDenyPolicyItems()); + policyItems.addAll(policy.getAllowExceptions()); + policyItems.addAll(policy.getDenyExceptions()); + + if (CollectionUtils.isEmpty(policyItems)) { + return; + } + + Map> impliedAccessGrants = ServiceDefUtil.getExpandedImpliedGrants(getServiceDef()); + + for (RangerPolicyItem policyItem : policyItems) { + if (!isPolicyItemValidityActive(policyItem, request)) { + removeAccessesForPrincipal(policyItem, impliedAccessGrants, user, groups, roles, resourceACLs); + } + } + } + + private boolean isPolicyItemValidityActive(RangerPolicyItem policyItem, RangerAccessRequest request) { + if (policyItem == null || request == null || CollectionUtils.isEmpty(policyItem.getConditions())) { + return true; + } + + for (RangerPolicy.RangerPolicyItemCondition condition : policyItem.getConditions()) { + if (!StringUtils.equalsIgnoreCase(condition.getType(), "validitySchedule")) { + continue; + } + + RangerValidityScheduleConditionEvaluator evaluator = new RangerValidityScheduleConditionEvaluator(); + evaluator.setPolicyItemCondition(condition); + evaluator.init(); + + if (!evaluator.isMatched(request)) { + return false; + } + } + + return true; + } + + private void removeAccessesForPrincipal(RangerPolicyItem policyItem, + Map> impliedAccessGrants, + String user, + Set groups, + Set roles, + RangerResourceACLs resourceACLs) { + if (policyItem == null || CollectionUtils.isEmpty(policyItem.getAccesses())) { + return; + } + + for (RangerPolicyItemAccess access : policyItem.getAccesses()) { + Collection accessTypes = impliedAccessGrants.get(access.getType()); + if (CollectionUtils.isEmpty(accessTypes)) { + accessTypes = Collections.singleton(access.getType()); + } + + if (StringUtils.isNotBlank(user) && CollectionUtils.isNotEmpty(policyItem.getUsers())) { + if (policyItem.getUsers().contains(user) || policyItem.getUsers().contains(RangerPolicyEngine.USER_CURRENT)) { + removeAccessTypes(resourceACLs.getUserACLs(), user, accessTypes); + } + } + + if (CollectionUtils.isNotEmpty(groups) && CollectionUtils.isNotEmpty(policyItem.getGroups())) { + if (policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC)) { + removeAccessTypes(resourceACLs.getGroupACLs(), RangerPolicyEngine.GROUP_PUBLIC, accessTypes); + } else { + for (String group : groups) { + if (policyItem.getGroups().contains(group)) { + removeAccessTypes(resourceACLs.getGroupACLs(), group, accessTypes); + } + } + } + } + + if (CollectionUtils.isNotEmpty(roles) && CollectionUtils.isNotEmpty(policyItem.getRoles())) { + for (String role : roles) { + if (policyItem.getRoles().contains(role)) { + removeAccessTypes(resourceACLs.getRoleACLs(), role, accessTypes); + } + } + } + } + } + + private void removeAccessTypes(Map> aclMap, String principal, Collection accessTypes) { + if (MapUtils.isEmpty(aclMap) || StringUtils.isBlank(principal) || CollectionUtils.isEmpty(accessTypes)) { + return; + } + + Map accessInfo = aclMap.get(principal); + if (MapUtils.isEmpty(accessInfo)) { + return; + } + + for (String accessType : accessTypes) { + accessInfo.remove(accessType); + } + + if (accessInfo.isEmpty()) { + aclMap.remove(principal); + } + } + private void updateRowFiltersFromPolicy(boolean isConditional, RangerResourceACLs resourceACLs, Set targetAccessTypes) { PolicyACLSummary aclSummary = getPolicyACLSummary(); diff --git a/agents-common/src/test/resources/policyengine/gds/gds_info_hive_access.json b/agents-common/src/test/resources/policyengine/gds/gds_info_hive_access.json index 96b399c850d..ded51dea174 100644 --- a/agents-common/src/test/resources/policyengine/gds/gds_info_hive_access.json +++ b/agents-common/src/test/resources/policyengine/gds/gds_info_hive_access.json @@ -8,6 +8,19 @@ "policyItems":[ { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "ds-user", "ds1-user" ], "groups": []} ] + }, + { "id": 2010, "name": "dataset-1-expired", "isEnabled": true, "isAuditEnabled": true, + "resources": { "dataset-id": { "values": ["1"] } }, + "policyItems":[ + { + "accesses":[ { "type": "_READ", "isAllowed": true } ], + "users": [ "expired-user" ], + "groups": [], + "conditions": [ + { "type": "validitySchedule", "values": [ "{\"startTime\":\"2000/01/01 00:00:00\",\"endTime\":\"2000/01/02 00:00:00\",\"timeZone\":\"UTC\"}" ] } + ] + } + ] } ] }, diff --git a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_access.json b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_access.json index 6ae15d4a128..ddbd3a8be73 100644 --- a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_access.json +++ b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_access.json @@ -303,6 +303,25 @@ { "name": "ACLs: table: sales.prospects", "request": { "resource": { "elements": { "database": "sales", "table": "prospects" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, + "ds1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, + "expired-user": { "select": { "result": 2, "isFinal": true, "policy": { "id": 2010 } } }, + "proj-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } }, + "proj1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } } + }, + "datasets": [ "dataset-1" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: table: sales.prospects, user: expired-user, expired validitySchedule", + "request": { + "resource": { "elements": { "database": "sales", "table": "prospects" } }, + "user": "expired-user", + "userGroups": [] + }, "acls": { "userACLs": { "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, @@ -321,6 +340,7 @@ "userACLs": { "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, "ds1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, + "expired-user": { "select": { "result": 2, "isFinal": true, "policy": { "id": 2010 } } }, "proj-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } }, "proj1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } } }, @@ -340,6 +360,7 @@ "userACLs": { "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, "ds1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, + "expired-user": { "select": { "result": 2, "isFinal": true, "policy": { "id": 2010 } } }, "proj-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } }, "proj1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } } }, @@ -360,6 +381,7 @@ "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2002 } } }, "ds1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, "ds2-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2002 } } }, + "expired-user": { "select": { "result": 2, "isFinal": true, "policy": { "id": 2010 } } }, "proj-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } }, "proj1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } } }, @@ -375,6 +397,7 @@ "ds-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2002 } } }, "ds1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2001 } } }, "ds2-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 2002 } } }, + "expired-user": { "select": { "result": 2, "isFinal": true, "policy": { "id": 2010 } } }, "proj-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } }, "proj1-user": { "select": { "result": 1, "isFinal": true, "policy": { "id": 3001 } } } },