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 a664de553 RANGER-4655: Execute and read permissions granted to a user in different HDFS policies does not take effect a664de553 is described below commit a664de553120f165d927e962e3677fe1abd0d722 Author: Abhay Kulkarni <ab...@apache.org> AuthorDate: Mon Jan 15 17:02:43 2024 -0800 RANGER-4655: Execute and read permissions granted to a user in different HDFS policies does not take effect --- .../policyengine/RangerPolicyEngineImpl.java | 16 ++++ .../RangerDefaultPolicyEvaluator.java | 35 +++++--- .../plugin/util/RangerAccessRequestUtil.java | 39 +++++++++ .../plugin/policyengine/TestPolicyEngine.java | 7 ++ .../test_policyengine_hdfs_multiple_accesses.json | 92 ++++++++++++++++++++++ 5 files changed, 179 insertions(+), 10 deletions(-) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java index 252482c8e..df39467ba 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java @@ -763,6 +763,22 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { } } + if (!request.isAccessTypeAny()) { + Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); + if (CollectionUtils.size(allRequestedAccesses) > 1 && !RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) { + Map<String, RangerAccessResult> accessTypeResults = RangerAccessRequestUtil.getAccessTypeResults(request.getContext()); + if (accessTypeResults != null) { + if (accessTypeResults.keySet().containsAll(allRequestedAccesses)) { + // Allow + RangerAccessResult result = accessTypeResults.values().iterator().next(); // Pick one result randomly + ret.setAccessResultFrom(result); + ret.setIsAccessDetermined(true); + } + RangerAccessRequestUtil.setAccessTypeResults(request.getContext(), null); + } + } + } + if (!ret.getIsAccessDetermined()) { if (isDeniedByTags) { ret.setIsAllowed(false); 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 7fe2a2eb3..ded8d0993 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 @@ -818,11 +818,29 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator } else { Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); - if (CollectionUtils.isNotEmpty(allRequestedAccesses)) { + if (CollectionUtils.size(allRequestedAccesses) > 1) { for (String accessType : allRequestedAccesses) { - accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getUserRoles(), accessType); - if (accessResult == null) { - break; + Integer oneAccessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getUserRoles(), accessType); + if (oneAccessResult != null) { + if (oneAccessResult.equals(RangerPolicyEvaluator.ACCESS_DENIED)) { + accessResult = oneAccessResult; + RangerAccessRequestUtil.setAccessTypeResults(request.getContext(), null); + + break; + } + if (oneAccessResult.equals(RangerPolicyEvaluator.ACCESS_ALLOWED)) { + if (!result.getIsAllowed()) { // if access is not yet allowed by another policy + if (matchType != RangerPolicyResourceMatcher.MatchType.ANCESTOR) { + RangerAccessResult oneResult = new RangerAccessResult(result.getPolicyType(), result.getServiceName(), result.getServiceDef(), result.getAccessRequest()); + oneResult.setIsAllowed(true); + oneResult.setPolicyPriority(getPolicyPriority()); + oneResult.setPolicyId(getPolicyId()); + oneResult.setPolicyVersion(getPolicy().getVersion()); + + RangerAccessRequestUtil.setAccessTypeResult(request.getContext(), accessType, oneResult); + } + } + } } } } else { @@ -865,7 +883,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator updateAccessResult(oneResult, matchType, false, "matched deny-all-else policy"); } - if (request.isAccessTypeAny() || RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) { + if (request.isAccessTypeAny() || allRequestedAccesses.size() == 1 || RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext())) { // Implement OR logic if (oneResult.getIsAllowed()) { allowResult = oneResult; @@ -886,14 +904,11 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator // Implement AND logic if (oneResult.getIsAccessDetermined() && !oneResult.getIsAllowed()) { denyResult = oneResult; - allowResult = null; + RangerAccessRequestUtil.setAccessTypeResults(request.getContext(), null); break; } else if (oneResult.getIsAllowed()) { - allowResult = noResult ? null : oneResult; - } else { - noResult = true; - allowResult = null; + RangerAccessRequestUtil.setAccessTypeResult(request.getContext(), accessType, oneResult); } } } 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 92a4fe02e..a56ecb268 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 @@ -29,6 +29,7 @@ import org.apache.commons.collections.MapUtils; import org.apache.ranger.plugin.contextenricher.RangerTagForEval; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; import org.apache.ranger.plugin.policyengine.gds.GdsAccessResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +52,7 @@ public class RangerAccessRequestUtil { 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_ACCESS_TYPE_RESULTS = "_ACCESS_TYPE_RESULTS"; public static void setRequestTagsInContext(Map<String, Object> context, Set<RangerTagForEval> tags) { if(CollectionUtils.isEmpty(tags)) { @@ -322,4 +324,41 @@ public class RangerAccessRequestUtil { return ret != null && ret.size() == 1 ? ret.iterator().next() : null; } + + public static void setAccessTypeResults(Map<String, Object> context, Map<String, RangerAccessResult> accessTypeResults) { + if (context != null) { + if (accessTypeResults != null) { + context.put(KEY_CONTEXT_ACCESS_TYPE_RESULTS, accessTypeResults); + } else { + context.remove(KEY_CONTEXT_ACCESS_TYPE_RESULTS); + } + } + } + + public static Map<String, RangerAccessResult> getAccessTypeResults(Map<String, Object> context) { + Map<String, RangerAccessResult> ret = null; + + if (context != null) { + Object o = context.get(KEY_CONTEXT_ACCESS_TYPE_RESULTS); + if (o != null) { + ret = (Map<String, RangerAccessResult>)o; + } + } + + return ret; + } + + public static void setAccessTypeResult(Map<String, Object> context, String accessType, RangerAccessResult result) { + if (context != null) { + Map<String, RangerAccessResult> results = getAccessTypeResults(context); + + if (results == null) { + results = new HashMap<>(); + + setAccessTypeResults(context, results); + } + + results.putIfAbsent(accessType, result); + } + } } diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java index 2afbfebd4..64563b84e 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java @@ -509,6 +509,13 @@ public class TestPolicyEngine { runTestsFromResourceFiles(resourceFiles); } + @Test + public void testMultipleAccessAuthorization() throws Exception { + String[] resourceFiles = {"/policyengine/test_policyengine_hdfs_multiple_accesses.json"}; + + runTestsFromResourceFiles(resourceFiles); + } + private void runTestsFromResourceFiles(String[] resourceNames) { for(String resourceName : resourceNames) { InputStream inStream = this.getClass().getResourceAsStream(resourceName); diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_multiple_accesses.json b/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_multiple_accesses.json new file mode 100644 index 000000000..6b53d2e02 --- /dev/null +++ b/agents-common/src/test/resources/policyengine/test_policyengine_hdfs_multiple_accesses.json @@ -0,0 +1,92 @@ +{ + "serviceName":"hdfsdev", + + "serviceDef":{ + "name":"hdfs", + "id":1, + "resources":[ + {"name":"path","type":"path","level":1,"mandatory":true,"lookupSupported":true,"matcher":"org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher","matcherOptions":{"wildCard":true, "ignoreCase":true},"label":"Resource Path","description":"HDFS file or directory path"} + ], + "accessTypes":[ + {"name":"read","label":"Read"}, + {"name":"write","label":"Write"}, + {"name":"execute","label":"Execute"} + ], + "contextEnrichers": + [ + { + "itemId":1, + "name" : "GeolocationEnricher", + "enricher" : "org.apache.ranger.plugin.contextenricher.RangerFileBasedGeolocationProvider", + "enricherOptions" : { + "FilePath":"/etc/ranger/geo/geo.txt", "ForceRead":"false", "IPInDotFormat":"true" + ,"geolocation.meta.prefix": "TEST_" + } + } + ], + "policyConditions": [ + { + "itemId":1, + "name":"ScriptConditionEvaluator", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", + "evaluatorOptions" : {"engineName":"JavaScript"}, + "label":"Script", + "description": "Script to execute" + } + ] + }, + + "policies":[ + {"id":1,"name":"audit-all-access under /public","isEnabled":true,"isAuditEnabled":true, + "resources":{"path":{"values":["/public"],"isRecursive":true}}, + "policyItems":[ + {"accesses":[],"users":[],"groups":["public"],"delegateAdmin":false} + ] + } + , + {"id":2,"name":"allow-execute-to-all under /public/","isEnabled":true,"isAuditEnabled":false, + "resources":{"path":{"values":["/public/*"],"isRecursive":true}}, + "policyItems":[ + {"accesses":[{"type":"execute","isAllowed":true}],"users":[],"groups":["public"],"delegateAdmin":false} + ] + } + , + {"id":3,"name":"allow-read-to-finance under /public/finance","isEnabled":true,"isAuditEnabled":true, + "resources":{"path":{"values":["/public/finance"],"isRecursive":true}}, + "policyItems":[ + {"accesses":[{"type":"read","isAllowed":true}],"users":["finance"],"groups":[],"delegateAdmin":false} + ] + } + ], + + "tests":[ + {"name":"ALLOW 'read_execute /public/finance' for user finance", + "request":{ + "resource":{"elements":{"path":"/public/finance"}}, + "accessType":"read","user":"finance","userGroups":[],"requestData":"read_execute /public/finance", + "context": {"ACCESSTYPES": [ "read", "execute" ]} + + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":3} + } + , + {"name":"DENY 'read_execute /public/finance' for user hr", + "request":{ + "resource":{"elements":{"path":"/public/finance"}}, + "accessType":"read","user":"hr","userGroups":[],"requestData":"read_execute /public/finance", + "context": {"ACCESSTYPES": [ "read", "execute" ]} + + }, + "result":{"isAudited":true,"isAllowed":false,"policyId":-1} + } + , + {"name":"ALLOW 'execute /public/finance' for user hr", + "request":{ + "resource":{"elements":{"path":"/public/finance"}}, + "accessType":"execute","user":"hr","userGroups":[],"requestData":"execute /public/finance" + }, + "result":{"isAudited":true,"isAllowed":true,"policyId":2} + } + ] +} +