You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2023/02/23 00:18:31 UTC

[ranger] branch ranger-2.4 updated: RANGER-4100: Efficient computation of the smallest set of evaluators returned by search of multiple Trie trees

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

madhan pushed a commit to branch ranger-2.4
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/ranger-2.4 by this push:
     new 7ec75608e RANGER-4100: Efficient computation of the smallest set of evaluators returned by search of multiple Trie trees
7ec75608e is described below

commit 7ec75608e7bcdfe286885fecaf00ea3a8d7a318f
Author: Abhay Kulkarni <ab...@apache.org>
AuthorDate: Mon Feb 20 14:11:05 2023 -0800

    RANGER-4100: Efficient computation of the smallest set of evaluators returned by search of multiple Trie trees
    
    (cherry picked from commit 85f5483ed444bf40caa588ec5b788a51532c3095)
---
 .../plugin/contextenricher/RangerTagEnricher.java  |  75 +---------
 .../validation/RangerSecurityZoneValidator.java    |  65 +--------
 .../ranger/plugin/policyengine/PolicyEngine.java   | 111 ++++-----------
 .../util/RangerResourceEvaluatorsRetriever.java    | 158 +++++++++++++++++++++
 .../plugin/policyengine/TestPolicyEngine.java      |   3 +-
 5 files changed, 195 insertions(+), 217 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
index da06e4161..93d1e9d08 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
@@ -44,6 +44,7 @@ import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerCommonConstants;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 import org.apache.ranger.plugin.util.RangerReadWriteLock;
+import org.apache.ranger.plugin.util.RangerResourceEvaluatorsRetriever;
 import org.apache.ranger.plugin.util.RangerServiceNotFoundException;
 import org.apache.ranger.plugin.util.RangerServiceTagsDeltaUtil;
 import org.apache.ranger.plugin.util.ServiceTags;
@@ -548,7 +549,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			RangerAccessRequestImpl  request = new RangerAccessRequestImpl();
 			request.setResource(accessResource);
 
-			List<RangerServiceResourceMatcher> oldMatchers = getEvaluators(request, enrichedServiceTags);
+			Collection<RangerServiceResourceMatcher> oldMatchers = getEvaluators(request, enrichedServiceTags);
 
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("Found [" + oldMatchers.size() + "] matchers for service-resource[" + serviceResource + "]");
@@ -669,7 +670,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			ret = enrichedServiceTags.getTagsForEmptyResourceAndAnyAccess();
 		} else {
 
-			final List<RangerServiceResourceMatcher> serviceResourceMatchers = getEvaluators(request, enrichedServiceTags);
+			final Collection<RangerServiceResourceMatcher> serviceResourceMatchers = getEvaluators(request, enrichedServiceTags);
 
 			if (CollectionUtils.isNotEmpty(serviceResourceMatchers)) {
 
@@ -715,11 +716,11 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 		return ret;
 	}
 
-	private List<RangerServiceResourceMatcher> getEvaluators(RangerAccessRequest request, EnrichedServiceTags enrichedServiceTags) {
+	private Collection<RangerServiceResourceMatcher> getEvaluators(RangerAccessRequest request, EnrichedServiceTags enrichedServiceTags) {
 		if(LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerTagEnricher.getEvaluators(request=" + request + ")");
 		}
-		List<RangerServiceResourceMatcher>  ret        = Collections.EMPTY_LIST;
+		Collection<RangerServiceResourceMatcher>  ret;
 
 		RangerAccessResource                resource   = request.getResource();
 
@@ -734,71 +735,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 				perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, "RangerTagEnricher.getEvaluators(resource=" + resource.getAsString() + ")");
 			}
 
-			List<String>                            resourceKeys = serviceDefHelper.getOrderedResourceNames(resource.getKeys());
-			Set<RangerServiceResourceMatcher>       smallestList = null;
-
-			if (CollectionUtils.isNotEmpty(resourceKeys)) {
-
-				for (String resourceName : resourceKeys) {
-					RangerResourceTrie<RangerServiceResourceMatcher> trie = serviceResourceTrie.get(resourceName);
-
-					if (trie == null) { // if no trie exists for this resource level, ignore and continue to next level
-						continue;
-					}
-
-					Set<RangerServiceResourceMatcher> serviceResourceMatchersForResource = trie.getEvaluatorsForResource(resource.getValue(resourceName), request.getResourceMatchingScope());
-					Set<RangerServiceResourceMatcher> inheritedResourceMatchers = trie.getInheritedEvaluators();
-
-					if (smallestList != null) {
-						if (CollectionUtils.isEmpty(inheritedResourceMatchers) && CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
-							smallestList = null;
-						} else if (CollectionUtils.isEmpty(inheritedResourceMatchers)) {
-							smallestList.retainAll(serviceResourceMatchersForResource);
-						} else if (CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
-							smallestList.retainAll(inheritedResourceMatchers);
-						} else {
-							Set<RangerServiceResourceMatcher> smaller, bigger;
-							if (serviceResourceMatchersForResource.size() < inheritedResourceMatchers.size()) {
-								smaller = serviceResourceMatchersForResource;
-								bigger = inheritedResourceMatchers;
-							} else {
-								smaller = inheritedResourceMatchers;
-								bigger = serviceResourceMatchersForResource;
-							}
-							Set<RangerServiceResourceMatcher> tmp = new HashSet<>();
-							if (smallestList.size() < smaller.size()) {
-								smallestList.stream().filter(smaller::contains).forEach(tmp::add);
-								smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-							} else {
-								smaller.stream().filter(smallestList::contains).forEach(tmp::add);
-								if (smallestList.size() < bigger.size()) {
-									smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-								} else {
-									bigger.stream().filter(smallestList::contains).forEach(tmp::add);
-								}
-							}
-							smallestList = tmp;
-						}
-					} else {
-						if (CollectionUtils.isEmpty(inheritedResourceMatchers) || CollectionUtils.isEmpty(serviceResourceMatchersForResource)) {
-							Set<RangerServiceResourceMatcher> tmp = CollectionUtils.isEmpty(inheritedResourceMatchers) ? serviceResourceMatchersForResource : inheritedResourceMatchers;
-							smallestList = resourceKeys.size() == 1 || CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
-						} else {
-							smallestList = new HashSet<>(serviceResourceMatchersForResource);
-							smallestList.addAll(inheritedResourceMatchers);
-						}
-					}
-
-					if (CollectionUtils.isEmpty(smallestList)) {// no tags for this resource, bail out
-						smallestList = null;
-						break;
-					}
-				}
-			}
-
-			if (smallestList != null) {
-				ret = new ArrayList<>(smallestList);
-			}
+			ret = RangerResourceEvaluatorsRetriever.getEvaluators(serviceResourceTrie, resource.getAsMap(), request.getResourceMatchingScope());
 
 			RangerPerfTracer.logAlways(perf);
 		}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
index f1045ad60..ca899979a 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerSecurityZoneValidator.java
@@ -35,11 +35,13 @@ import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatche
 import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
 import org.apache.ranger.plugin.store.SecurityZoneStore;
 import org.apache.ranger.plugin.store.ServiceStore;
+import org.apache.ranger.plugin.util.RangerResourceEvaluatorsRetriever;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -407,69 +409,12 @@ public class RangerSecurityZoneValidator extends RangerValidator {
         //       flag error if there are more than one matching evaluators with different zone-ids.
         //
 
-        RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef, true);
-
         for (RangerSecurityZone zone : zones) {
             List<HashMap<String, List<String>>> resources = zone.getServices().get(serviceName).getResources();
 
             for (Map<String, List<String>> resource : resources) {
 
-                Set<RangerZoneResourceMatcher>       smallestList     = null;
-
-                List<String> resourceKeys = serviceDefHelper.getOrderedResourceNames(resource.keySet());
-
-                for (String resourceDefName : resourceKeys) {
-                    List<String> resourceValues = resource.get(resourceDefName);
-
-                    RangerResourceTrie<RangerZoneResourceMatcher> trie = trieMap.get(resourceDefName);
-
-                    Set<RangerZoneResourceMatcher> zoneMatchersForResource = trie.getEvaluatorsForResource(resourceValues);
-                    Set<RangerZoneResourceMatcher> inheritedZoneMatchers = trie.getInheritedEvaluators();
-
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("ResourceDefName:[" + resourceDefName + "], values:[" + resourceValues + "], matched-zones:[" + zoneMatchersForResource + "], inherited-zones:[" + inheritedZoneMatchers + "]");
-                    }
-
-                    if (smallestList != null) {
-                        if (CollectionUtils.isEmpty(inheritedZoneMatchers) && CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                            smallestList = null;
-                        } else if (CollectionUtils.isEmpty(inheritedZoneMatchers)) {
-                            smallestList.retainAll(zoneMatchersForResource);
-                        } else if (CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                            smallestList.retainAll(inheritedZoneMatchers);
-                        } else {
-                            Set<RangerZoneResourceMatcher> smaller, bigger;
-                            if (zoneMatchersForResource.size() < inheritedZoneMatchers.size()) {
-                                smaller = zoneMatchersForResource;
-                                bigger = inheritedZoneMatchers;
-                            } else {
-                                smaller = inheritedZoneMatchers;
-                                bigger = zoneMatchersForResource;
-                            }
-                            Set<RangerZoneResourceMatcher> tmp = new HashSet<>();
-                            if (smallestList.size() < smaller.size()) {
-                                smallestList.stream().filter(smaller::contains).forEach(tmp::add);
-                                smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-                            } else {
-                                smaller.stream().filter(smallestList::contains).forEach(tmp::add);
-                                if (smallestList.size() < bigger.size()) {
-                                    smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-                                } else {
-                                    bigger.stream().filter(smallestList::contains).forEach(tmp::add);
-                                }
-                            }
-                            smallestList = tmp;
-                        }
-                    } else {
-                        if (CollectionUtils.isEmpty(inheritedZoneMatchers) || CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                            Set<RangerZoneResourceMatcher> tmp = CollectionUtils.isEmpty(inheritedZoneMatchers) ? zoneMatchersForResource : inheritedZoneMatchers;
-                            smallestList = resourceKeys.size() == 1 || CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
-                        } else {
-                            smallestList = new HashSet<>(zoneMatchersForResource);
-                            smallestList.addAll(inheritedZoneMatchers);
-                        }
-                    }
-                }
+                Collection<RangerZoneResourceMatcher> smallestList = RangerResourceEvaluatorsRetriever.getEvaluators(trieMap, resource);
 
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Resource:[" + resource +"], matched-zones:[" + smallestList +"]");
@@ -479,8 +424,6 @@ public class RangerSecurityZoneValidator extends RangerValidator {
                     continue;
                 }
 
-                final Set<RangerZoneResourceMatcher> intersection = smallestList;
-
                 RangerAccessResourceImpl accessResource = new RangerAccessResourceImpl();
 
                 accessResource.setServiceDef(serviceDef);
@@ -491,7 +434,7 @@ public class RangerSecurityZoneValidator extends RangerValidator {
 
                 Set<String> matchedZoneNames = new HashSet<>();
 
-                for (RangerZoneResourceMatcher zoneMatcher : intersection) {
+                for (RangerZoneResourceMatcher zoneMatcher : smallestList) {
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("Trying to match resource:[" + accessResource +"] using zoneMatcher:[" + zoneMatcher + "]");
                     }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
index f44570623..3864f30d2 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
@@ -21,6 +21,8 @@ package org.apache.ranger.plugin.policyengine;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -28,14 +30,12 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.ListUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicyDelta;
 import org.apache.ranger.plugin.model.RangerServiceDef;
-import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
 import org.apache.ranger.plugin.model.validation.RangerZoneResourceMatcher;
 import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
@@ -44,6 +44,7 @@ import org.apache.ranger.plugin.service.RangerAuthContext;
 import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 import org.apache.ranger.plugin.util.RangerPolicyDeltaUtil;
+import org.apache.ranger.plugin.util.RangerResourceEvaluatorsRetriever;
 import org.apache.ranger.plugin.util.RangerReadWriteLock;
 import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.ServicePolicies;
@@ -62,7 +63,7 @@ public class PolicyEngine {
     private final List<RangerContextEnricher>         allContextEnrichers;
     private final RangerPluginContext                 pluginContext;
     private final Map<String, RangerPolicyRepository> zonePolicyRepositories = new HashMap<>();
-    private final Map<String, RangerResourceTrie>     resourceZoneTrie = new HashMap<>();
+    private final Map<String, RangerResourceTrie<RangerZoneResourceMatcher>>     resourceZoneTrie = new HashMap<>();
     private final Map<String, String>                 zoneTagServiceMap = new HashMap<>();
     private       boolean                             useForwardedIPAddress;
     private       String[]                            trustedProxyAddresses;
@@ -173,10 +174,10 @@ public class PolicyEngine {
     public List<RangerPolicy> getResourcePolicies(String zoneName) {
         RangerPolicyRepository zoneResourceRepository = zonePolicyRepositories.get(zoneName);
 
-        return zoneResourceRepository == null ? ListUtils.EMPTY_LIST : zoneResourceRepository.getPolicies();
+        return zoneResourceRepository == null ? Collections.emptyList() : zoneResourceRepository.getPolicies();
     }
 
-    Map<String, RangerResourceTrie> getResourceZoneTrie() {
+    Map<String, RangerResourceTrie<RangerZoneResourceMatcher>> getResourceZoneTrie() {
         return resourceZoneTrie;
     }
 
@@ -466,101 +467,39 @@ public class PolicyEngine {
         Set<String> ret = null;
 
         if (MapUtils.isNotEmpty(this.resourceZoneTrie)) {
-            Set<RangerZoneResourceMatcher>       smallestList     = null;
-            RangerServiceDefHelper               serviceDefHelper = policyRepository.getOptions().getServiceDefHelper();
 
-            List<String> resourceKeys = resource == null ? new ArrayList<>() : serviceDefHelper.getOrderedResourceNames(resource.keySet());
-
-            for (String resourceDefName : resourceKeys) {
-                RangerResourceTrie<RangerZoneResourceMatcher> trie = resourceZoneTrie.get(resourceDefName);
-
-                if (trie == null) {
-                    continue;
-                }
-
-                Object resourceValues = resource.get(resourceDefName);
-
-                Set<RangerZoneResourceMatcher> zoneMatchersForResource = trie.getEvaluatorsForResource(resourceValues);
-                Set<RangerZoneResourceMatcher> inheritedZoneMatchers = trie.getInheritedEvaluators();
-
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug("ResourceDefName:[" + resourceDefName + "], values:[" + resourceValues + "], matched-zones:[" + zoneMatchersForResource + "], inherited-zones:[" + inheritedZoneMatchers + "]");
-                }
-
-                if (smallestList != null) {
-                    if (CollectionUtils.isEmpty(inheritedZoneMatchers) && CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                        smallestList = null;
-                    } else if (CollectionUtils.isEmpty(inheritedZoneMatchers)) {
-                        smallestList.retainAll(zoneMatchersForResource);
-                    } else if (CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                        smallestList.retainAll(inheritedZoneMatchers);
-                    } else {
-                        Set<RangerZoneResourceMatcher> smaller, bigger;
-                        if (zoneMatchersForResource.size() < inheritedZoneMatchers.size()) {
-                            smaller = zoneMatchersForResource;
-                            bigger = inheritedZoneMatchers;
-                        } else {
-                            smaller = inheritedZoneMatchers;
-                            bigger = zoneMatchersForResource;
-                        }
-                        Set<RangerZoneResourceMatcher> tmp = new HashSet<>();
-                        if (smallestList.size() < smaller.size()) {
-                            smallestList.stream().filter(smaller::contains).forEach(tmp::add);
-                            smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-                        } else {
-                            smaller.stream().filter(smallestList::contains).forEach(tmp::add);
-                            if (smallestList.size() < bigger.size()) {
-                                smallestList.stream().filter(bigger::contains).forEach(tmp::add);
-                            } else {
-                                bigger.stream().filter(smallestList::contains).forEach(tmp::add);
-                            }
-                        }
-                        smallestList = tmp;
-                    }
-                } else {
-                    if (CollectionUtils.isEmpty(inheritedZoneMatchers) || CollectionUtils.isEmpty(zoneMatchersForResource)) {
-                        Set<RangerZoneResourceMatcher> tmp = CollectionUtils.isEmpty(inheritedZoneMatchers) ? zoneMatchersForResource : inheritedZoneMatchers;
-                        smallestList = resourceKeys.size() == 1 || CollectionUtils.isEmpty(tmp) ? tmp : new HashSet<>(tmp);
-                    } else {
-                        smallestList = new HashSet<>(zoneMatchersForResource);
-                        smallestList.addAll(inheritedZoneMatchers);
-                    }
-                }
-            }
+            Collection<RangerZoneResourceMatcher> smallestList = RangerResourceEvaluatorsRetriever.getEvaluators(resourceZoneTrie, resource);
 
             if (CollectionUtils.isNotEmpty(smallestList)) {
-                final Set<RangerZoneResourceMatcher> intersection = smallestList;
 
                 if (LOG.isDebugEnabled()) {
-                    LOG.debug("Resource:[" + resource + "], matched-zones:[" + intersection + "]");
+                    LOG.debug("Resource:[" + resource + "], matched-zones:[" + smallestList + "]");
                 }
 
-                if (intersection.size() > 0) {
-                    ret = new HashSet<>();
+                ret = new HashSet<>();
 
-                    for (RangerZoneResourceMatcher zoneMatcher : intersection) {
+                for (RangerZoneResourceMatcher zoneMatcher : smallestList) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Trying to match resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
+                    }
+
+                    // These are potential matches. Try to really match them
+                    if (zoneMatcher.getPolicyResourceMatcher().isMatch(accessResource, RangerPolicyResourceMatcher.MatchScope.ANY, null)) {
                         if (LOG.isDebugEnabled()) {
-                            LOG.debug("Trying to match resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
+                            LOG.debug("Matched resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
                         }
 
-                        // These are potential matches. Try to really match them
-                        if (zoneMatcher.getPolicyResourceMatcher().isMatch(accessResource, RangerPolicyResourceMatcher.MatchScope.ANY, null)) {
-                            if (LOG.isDebugEnabled()) {
-                                LOG.debug("Matched resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
-                            }
-
-                            // Actual match happened
-                            ret.add(zoneMatcher.getSecurityZoneName());
-                        } else {
-                            if (LOG.isDebugEnabled()) {
-                                LOG.debug("Did not match resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
-                            }
+                        // Actual match happened
+                        ret.add(zoneMatcher.getSecurityZoneName());
+                    } else {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Did not match resource:[" + accessResource + "] using zoneMatcher:[" + zoneMatcher + "]");
                         }
                     }
+                }
 
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("The following zone-names matched resource:[" + accessResource + "]: " + ret);
-                    }
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("The following zone-names matched resource:[" + accessResource + "]: " + ret);
                 }
             }
         }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceEvaluatorsRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceEvaluatorsRetriever.java
new file mode 100644
index 000000000..dfe591c59
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceEvaluatorsRetriever.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerResourceTrie;
+import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RangerResourceEvaluatorsRetriever {
+    private static final Logger LOG = LoggerFactory.getLogger(RangerResourceEvaluatorsRetriever.class);
+
+    public static <T  extends RangerResourceEvaluator> Collection<T> getEvaluators(Map<String, RangerResourceTrie<T>> resourceTrie, Map<String, ?> resource) {
+        return getEvaluators(resourceTrie, resource, RangerAccessRequest.ResourceMatchingScope.SELF);
+    }
+
+    public static <T  extends RangerResourceEvaluator> Collection<T> getEvaluators(Map<String, RangerResourceTrie<T>> resourceTrie, Map<String, ?> resource, RangerAccessRequest.ResourceMatchingScope scope) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerPolicyResourceEvaluatorsRetriever.getEvaluators(" + resource + ")");
+        }
+        Set<T> ret = null;
+
+        if (MapUtils.isNotEmpty(resourceTrie) && MapUtils.isNotEmpty(resource)) {
+            Set<String> resourceKeys = resource.keySet();
+
+            List<Evaluators<T>> sortedEvaluators = new ArrayList<>(resourceKeys.size());
+
+            for (String resourceDefName : resourceKeys) {
+                RangerResourceTrie<T> trie = resourceTrie.get(resourceDefName);
+
+                if (trie == null) {
+                    continue;
+                }
+
+                Object resourceValues = resource.get(resourceDefName);
+
+                Set<T> inheritedMatchers   = trie.getInheritedEvaluators();
+                Set<T> matchersForResource = trie.getEvaluatorsForResource(resourceValues, scope);
+
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("ResourceDefName:[" + resourceDefName + "], values:[" + resourceValues + "], resource-matchers:[" + matchersForResource + "], inherited-matchers:[" + inheritedMatchers + "]");
+                }
+                if (CollectionUtils.isEmpty(inheritedMatchers) && CollectionUtils.isEmpty(matchersForResource)) {
+                    sortedEvaluators.clear();
+                    break;
+                }
+                sortedEvaluators.add(new Evaluators<>(inheritedMatchers, matchersForResource));
+            }
+
+            if (CollectionUtils.isNotEmpty(sortedEvaluators)) {
+                Collections.sort(sortedEvaluators);
+
+                ret = sortedEvaluators.remove(0).getMatchers();
+
+                for (Evaluators<T> evaluators : sortedEvaluators) {
+                    if (CollectionUtils.isEmpty(evaluators.inheritedMatchers)) {
+                        ret.retainAll(evaluators.resourceMatchers);
+                    } else if (CollectionUtils.isEmpty(evaluators.resourceMatchers)) {
+                        ret.retainAll(evaluators.inheritedMatchers);
+                    } else {
+                        Set<T> smaller = evaluators.getSmaller();
+                        Set<T> bigger  = evaluators.getBigger();
+
+                        Set<T> tmp = new HashSet<>(ret.size());
+
+                        if (ret.size() < smaller.size()) {
+                            ret.stream().filter(smaller::contains).forEach(tmp::add);
+                            ret.stream().filter(bigger::contains).forEach(tmp::add);
+                        } else {
+                            smaller.stream().filter(ret::contains).forEach(tmp::add);
+                            if (ret.size() < bigger.size()) {
+                                ret.stream().filter(bigger::contains).forEach(tmp::add);
+                            } else {
+                                bigger.stream().filter(ret::contains).forEach(tmp::add);
+                            }
+                        }
+                        ret = tmp;
+                    }
+                    if (ret.isEmpty()) {
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RangerResourceEvaluatorsRetriever.getEvaluators(" + resource + ") : evaluator:[" + ret + "]");
+        }
+        return ret;
+    }
+
+    static class Evaluators<T> implements Comparable<Evaluators<T>> {
+        private final Set<T> inheritedMatchers;
+        private final Set<T> resourceMatchers;
+        private final Set<T> smaller;
+        private final Set<T> bigger;
+        private final int    size;
+
+        Evaluators(Set<T> inherited, Set<T> matched) {
+            inheritedMatchers = inherited == null ? Collections.emptySet() : inherited;
+            resourceMatchers  = matched   == null ? Collections.emptySet() : matched;
+            size              = inheritedMatchers.size() + resourceMatchers.size();
+            smaller           = inheritedMatchers.size() < resourceMatchers.size() ? inheritedMatchers : resourceMatchers;
+            bigger            = smaller == inheritedMatchers ? resourceMatchers : inheritedMatchers;
+        }
+
+        // Should be called at most once
+        Set<T> getMatchers() {
+            Set<T> ret = new HashSet<>(size);
+
+            ret.addAll(inheritedMatchers);
+            ret.addAll(resourceMatchers);
+
+            return ret;
+        }
+
+        Set<T> getSmaller() {
+            return smaller;
+        }
+
+        Set<T> getBigger() {
+            return bigger;
+        }
+
+        @Override
+        public int compareTo(Evaluators<T> other) {
+            return Integer.compare(size, other.size);
+        }
+    }
+}
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 eb3d0ff46..632d7cf7e 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
@@ -44,6 +44,7 @@ import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerServiceResource;
 import org.apache.ranger.plugin.model.RangerValiditySchedule;
 import org.apache.ranger.plugin.model.validation.RangerValidityScheduleValidator;
+import org.apache.ranger.plugin.model.validation.RangerZoneResourceMatcher;
 import org.apache.ranger.plugin.model.validation.ValidationFailureDetails;
 import org.apache.ranger.plugin.policyengine.TestPolicyEngine.PolicyEngineTestCase.TestData;
 import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.RangerPolicyResourceEvaluator;
@@ -958,7 +959,7 @@ public class TestPolicyEngine {
 			ret = Objects.equals(me.getResourceZoneTrie().keySet(), other.getResourceZoneTrie().keySet());
 
 			if (ret) {
-				for (Map.Entry<String, RangerResourceTrie> entry : me.getResourceZoneTrie().entrySet()) {
+				for (Map.Entry<String, RangerResourceTrie<RangerZoneResourceMatcher>> entry : me.getResourceZoneTrie().entrySet()) {
 					ret = compareSubtree(entry.getValue(), other.getResourceZoneTrie().get(entry.getKey()));
 
 					if (!ret) {