You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by rm...@apache.org on 2026/05/26 16:41:48 UTC

(ranger) 01/01: RANGER-5610:getResourceACLs for a principal should consider validitySchedule of principal for ACL creation

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

rameeshm pushed a commit to branch RANGER-5610-patch
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit eb67dfbdfe7d784d89374076e036f01576c20867
Author: Ramesh Mani <rm...@apache.org>
AuthorDate: Tue May 26 09:41:06 2026 -0700

    RANGER-5610:getResourceACLs for a principal should consider validitySchedule of principal for ACL creation
---
 .../RangerAbstractPolicyEvaluator.java             | 128 +++++++++++++++++++++
 .../policyengine/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 7c45f6dfb..a55f8535f 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<String> groups = request.getUserGroups();
+        Set<String> roles  = request.getUserRoles();
+
+        if (StringUtils.isBlank(user) && CollectionUtils.isEmpty(groups) && CollectionUtils.isEmpty(roles)) {
+            return;
+        }
+
+        RangerPolicy policy = getPolicy();
+        if (policy == null) {
+            return;
+        }
+
+        List<RangerPolicyItem> 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<String, Collection<String>> 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<String, Collection<String>> impliedAccessGrants,
+            String user,
+            Set<String> groups,
+            Set<String> roles,
+            RangerResourceACLs resourceACLs) {
+        if (policyItem == null || CollectionUtils.isEmpty(policyItem.getAccesses())) {
+            return;
+        }
+
+        for (RangerPolicyItemAccess access : policyItem.getAccesses()) {
+            Collection<String> 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<String, Map<String, RangerResourceACLs.AccessResult>> aclMap, String principal, Collection<String> accessTypes) {
+        if (MapUtils.isEmpty(aclMap) || StringUtils.isBlank(principal) || CollectionUtils.isEmpty(accessTypes)) {
+            return;
+        }
+
+        Map<String, RangerResourceACLs.AccessResult> 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<String> 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 96b399c85..ded51dea1 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 6ae15d4a1..ddbd3a8be 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 } } }
         },