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/06/06 03:42:33 UTC

[ranger] branch master updated: RANGER-4165: support SELF_OR_PREFIX resource matching scope

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

madhan 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 f33a88a90 RANGER-4165: support SELF_OR_PREFIX resource matching scope
f33a88a90 is described below

commit f33a88a90318ecd06fbdfeea10f65d709c3b9100
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Sun May 14 15:51:06 2023 -0700

    RANGER-4165: support SELF_OR_PREFIX resource matching scope
---
 .../RangerServiceResourceMatcher.java              |   5 +-
 .../plugin/contextenricher/RangerTagEnricher.java  |   7 +-
 .../plugin/policyengine/RangerAccessRequest.java   |  13 +-
 .../policyengine/RangerAccessRequestImpl.java      |  11 ++
 .../policyengine/RangerAccessRequestReadOnly.java  |   3 +
 .../policyengine/RangerAccessRequestWrapper.java   |   3 +
 .../policyengine/RangerPolicyEngineImpl.java       |   4 +-
 .../policyengine/RangerPolicyRepository.java       |   2 +-
 .../plugin/policyengine/RangerResourceTrie.java    |  88 +++++++--
 .../RangerAuditPolicyEvaluator.java                |   2 +-
 .../RangerDefaultPolicyEvaluator.java              |   8 +-
 .../RangerDefaultPolicyResourceMatcher.java        |  39 +++-
 .../RangerPolicyResourceMatcher.java               |  11 ++
 .../RangerAbstractResourceMatcher.java             |  69 ++++---
 .../RangerDefaultResourceMatcher.java              |  20 +-
 .../resourcematcher/RangerPathResourceMatcher.java | 215 +++++++++++++--------
 .../resourcematcher/RangerResourceMatcher.java     |   3 +-
 .../resourcematcher/RangerURLResourceMatcher.java  |  20 +-
 .../plugin/resourcematcher/ResourceMatcher.java    |  53 +++--
 .../util/RangerResourceEvaluatorsRetriever.java    |  12 +-
 .../plugin/policyengine/TestPathResourceTrie.java  |  22 ++-
 .../plugin/policyengine/TestPolicyEngine.java      |  14 ++
 .../RangerAbstractResourceMatcherTest.java         |   3 +-
 .../RangerDefaultResourceMatcherTest.java          |   3 +-
 .../RangerPathResourceMatcherTest.java             |   7 +-
 .../RangerURLResourceMatcherTest.java              |   3 +-
 .../resourcematcher/TestResourceMatcher.java       |   3 +-
 .../test/resources/policyengine/aws_s3_tags.json   |  33 ++++
 .../policyengine/test_policyengine_aws.json        |  24 +--
 .../policyengine/test_policyengine_aws_s3.json     | 211 ++++++++++++++++++++
 .../policyengine/test_policyengine_kafka.json      | 157 +++++++++++++++
 31 files changed, 873 insertions(+), 195 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerServiceResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerServiceResourceMatcher.java
index 465d7d375..e696db518 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerServiceResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerServiceResourceMatcher.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.contextenricher;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerServiceResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyengine.RangerAccessResource;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
 import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
@@ -70,8 +71,8 @@ public class RangerServiceResourceMatcher implements RangerResourceEvaluator {
 		return ServiceDefUtil.isAncestorOf(policyResourceMatcher.getServiceDef(), leafResourceDef, resourceDef);
 	}
 
-	public RangerPolicyResourceMatcher.MatchType getMatchType(RangerAccessResource requestedResource, Map<String, Object> evalContext) {
-		return policyResourceMatcher != null ?  policyResourceMatcher.getMatchType(requestedResource, evalContext) : RangerPolicyResourceMatcher.MatchType.NONE;
+	public RangerPolicyResourceMatcher.MatchType getMatchType(RangerAccessResource requestedResource, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext) {
+		return policyResourceMatcher != null ? policyResourceMatcher.getMatchType(requestedResource, scopes, evalContext) : RangerPolicyResourceMatcher.MatchType.NONE;
 	}
 
 	static class IdComparator implements Comparator<RangerServiceResourceMatcher>, Serializable {
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 e0a86c398..b5428cfdf 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
@@ -564,7 +564,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 				List<RangerServiceResourceMatcher> notMatched = new ArrayList<>();
 
 				for (RangerServiceResourceMatcher resourceMatcher : oldMatchers) {
-					final RangerPolicyResourceMatcher.MatchType matchType = resourceMatcher.getMatchType(accessResource, request.getContext());
+					final RangerPolicyResourceMatcher.MatchType matchType = resourceMatcher.getMatchType(accessResource, request.getResourceElementMatchingScopes(), request.getContext());
 
 					if (LOG.isDebugEnabled()) {
 						LOG.debug("resource:[" + accessResource + ", MatchType:[" + matchType + "]");
@@ -703,10 +703,9 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			final Collection<RangerServiceResourceMatcher> serviceResourceMatchers = getEvaluators(request, enrichedServiceTags);
 
 			if (CollectionUtils.isNotEmpty(serviceResourceMatchers)) {
-
 				for (RangerServiceResourceMatcher resourceMatcher : serviceResourceMatchers) {
 
-					final RangerPolicyResourceMatcher.MatchType matchType = resourceMatcher.getMatchType(resource, request.getContext());
+					final RangerPolicyResourceMatcher.MatchType matchType = resourceMatcher.getMatchType(resource, request.getResourceElementMatchingScopes(), request.getContext());
 
 					if (LOG.isDebugEnabled()) {
 						LOG.debug("resource:[" + resource + ", MatchType:[" + matchType + "]");
@@ -771,7 +770,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 				perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, "RangerTagEnricher.getEvaluators(resource=" + resource.getAsString() + ")");
 			}
 
-			ret = RangerResourceEvaluatorsRetriever.getEvaluators(serviceResourceTrie, resource.getAsMap(), request.getResourceMatchingScope());
+			ret = RangerResourceEvaluatorsRetriever.getEvaluators(serviceResourceTrie, resource.getAsMap(), request.getResourceElementMatchingScopes());
 
 			RangerPerfTracer.logAlways(perf);
 		}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java
index 6a38747f4..01848df76 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java
@@ -19,14 +19,13 @@
 
 package org.apache.ranger.plugin.policyengine;
 
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 public interface RangerAccessRequest {
-	String RANGER_ACCESS_REQUEST_SCOPE_STRING = "Scope";
-
 	RangerAccessResource getResource();
 
 	String getAccessType();
@@ -67,5 +66,13 @@ public interface RangerAccessRequest {
 
 	ResourceMatchingScope getResourceMatchingScope();
 
-	enum ResourceMatchingScope {SELF, SELF_OR_DESCENDANTS, SELF_OR_CHILD}
+	default Map<String, ResourceElementMatchingScope> getResourceElementMatchingScopes() {
+		return Collections.emptyMap();
+	}
+
+	enum ResourceMatchingScope { SELF, SELF_OR_DESCENDANTS }
+
+	enum ResourceElementMatchingScope { SELF, SELF_OR_CHILD, SELF_OR_PREFIX }
+
+	enum ResourceElementMatchType { NONE, SELF, CHILD, PREFIX }
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
index e561c4c7c..019a0d893 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.plugin.policyengine;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -56,6 +57,7 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
 	private boolean isAccessTypeAny;
 	private boolean isAccessTypeDelegatedAdmin;
 	private ResourceMatchingScope resourceMatchingScope = ResourceMatchingScope.SELF;
+	private Map<String, ResourceElementMatchingScope> resourceElementMatchingScopes = Collections.emptyMap();
 
 	public RangerAccessRequestImpl() {
 		this(null, null, null, null, null);
@@ -96,6 +98,7 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
 		setContext(request.getContext());
 		setClusterName(request.getClusterName());
 		setResourceMatchingScope(request.getResourceMatchingScope());
+		setResourceElementMatchingScopes(request.getResourceElementMatchingScopes());
 		setClientIPAddress(request.getClientIPAddress());
 		setClusterType(request.getClusterType());
 	}
@@ -171,6 +174,9 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
 		return resourceMatchingScope;
 	}
 
+	@Override
+	public Map<String, ResourceElementMatchingScope> getResourceElementMatchingScopes() { return this.resourceElementMatchingScopes; }
+
 	@Override
 	public boolean isAccessTypeAny() {
 		return isAccessTypeAny;
@@ -265,6 +271,10 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
 		}
 	}
 
+	public void setResourceElementMatchingScopes(Map<String, ResourceElementMatchingScope> resourceElementMatchingScopes) {
+		this.resourceElementMatchingScopes = resourceElementMatchingScopes == null ? Collections.emptyMap() : resourceElementMatchingScopes;
+	}
+
 	public void setContext(Map<String, Object> context) {
 		if (context == null) {
 			this.context = new HashMap<>();
@@ -358,6 +368,7 @@ public class RangerAccessRequestImpl implements RangerAccessRequest {
 		sb.append("requestData={").append(requestData).append("} ");
 		sb.append("sessionId={").append(sessionId).append("} ");
 		sb.append("resourceMatchingScope={").append(resourceMatchingScope).append("} ");
+		sb.append("resourceElementMatchingScopes={").append(resourceElementMatchingScopes).append("} ");
 		sb.append("clusterName={").append(clusterName).append("} ");
 		sb.append("clusterType={").append(clusterType).append("} ");
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java
index 4887c0112..b732dfab6 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java
@@ -98,6 +98,9 @@ public class RangerAccessRequestReadOnly implements RangerAccessRequest {
 	@Override
 	public ResourceMatchingScope getResourceMatchingScope() { return source.getResourceMatchingScope(); }
 
+	@Override
+	public Map<String, ResourceElementMatchingScope> getResourceElementMatchingScopes() { return source.getResourceElementMatchingScopes(); }
+
 	@Override
 	public String getClusterName() { return source.getClusterName();	}
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java
index 6aec330d7..96f851e9a 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java
@@ -101,5 +101,8 @@ public class RangerAccessRequestWrapper implements RangerAccessRequest {
     @Override
     public ResourceMatchingScope getResourceMatchingScope() { return request.getResourceMatchingScope(); }
 
+    @Override
+    public Map<String, ResourceElementMatchingScope> getResourceElementMatchingScopes() { return request.getResourceElementMatchingScopes(); }
+
 }
 
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 e75bb722c..8ba0b1a7f 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
@@ -318,7 +318,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 						for (RangerPolicyResourceEvaluator resourceEvaluator : evaluator.getResourceEvaluators()) {
 							RangerPolicyResourceMatcher matcher = resourceEvaluator.getPolicyResourceMatcher();
 
-							matchType = matcher.getMatchType(request.getResource(), request.getContext());
+							matchType = matcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext());
 							isMatched = isMatch(matchType, request.getResourceMatchingScope());
 
 							if (isMatched) {
@@ -326,7 +326,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 
 								break;
 							} else if (matcher.getNeedsDynamicEval() && !isConditionalMatch) {
-								MatchType dynWildCardMatch = resourceEvaluator.getMacrosReplaceWithWildcardMatcher(policyEngine).getMatchType(request.getResource(), request.getContext());
+								MatchType dynWildCardMatch = resourceEvaluator.getMacrosReplaceWithWildcardMatcher(policyEngine).getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext());
 
 								isConditionalMatch = isMatch(dynWildCardMatch, request.getResourceMatchingScope());
 							}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
index b5b26702c..68f4b5dfd 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyRepository.java
@@ -719,7 +719,7 @@ public class RangerPolicyRepository {
             perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, "RangerPolicyRepository.getLikelyMatchEvaluators(resource=" + resource.getAsString() + ")");
         }
 
-        Collection<RangerPolicyResourceEvaluator> smallestList = RangerResourceEvaluatorsRetriever.getEvaluators(resourceTrie, resource.getAsMap(), request.getResourceMatchingScope());
+        Collection<RangerPolicyResourceEvaluator> smallestList = RangerResourceEvaluatorsRetriever.getEvaluators(resourceTrie, resource.getAsMap(), request.getResourceElementMatchingScopes());
 
         if (smallestList != null) {
             if (smallestList.size() == 0) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
index f89d51e35..07eb5815c 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceTrie.java
@@ -25,6 +25,7 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
 import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
 import org.apache.ranger.plugin.resourcematcher.RangerAbstractResourceMatcher;
@@ -44,6 +45,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Stack;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
@@ -184,10 +186,10 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
     }
 
     public Set<T> getEvaluatorsForResource(Object resource) {
-        return getEvaluatorsForResource(resource, RangerAccessRequest.ResourceMatchingScope.SELF);
+        return getEvaluatorsForResource(resource, ResourceElementMatchingScope.SELF);
     }
 
-    public Set<T> getEvaluatorsForResource(Object resource, RangerAccessRequest.ResourceMatchingScope scope) {
+    public Set<T> getEvaluatorsForResource(Object resource, ResourceElementMatchingScope scope) {
         if (resource instanceof String) {
             return getEvaluatorsForResource((String) resource, scope);
         } else if (resource instanceof Collection) {
@@ -576,7 +578,7 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
         return str.substring(0, minIndex);
     }
 
-    private Set<T> getEvaluatorsForResource(String resource, RangerAccessRequest.ResourceMatchingScope scope) {
+    private Set<T> getEvaluatorsForResource(String resource, ResourceElementMatchingScope scope) {
         if(LOG.isDebugEnabled()) {
             LOG.debug("==> RangerResourceTrie.getEvaluatorsForResource(" + resource + ", " + scope + ")");
         }
@@ -643,10 +645,10 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
             ret = accumulatedEvaluators;
         }
 
-        boolean includeEvaluatorsOfChildResources = scope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD;
+        final boolean includeChildEvaluators = scope == ResourceElementMatchingScope.SELF_OR_CHILD || scope == ResourceElementMatchingScope.SELF_OR_PREFIX;
+        final Set<T>  childEvalautors        = includeChildEvaluators ? new HashSet<>() : null;
 
-        if (includeEvaluatorsOfChildResources) {
-            final Set<T>  childEvalautors     = new HashSet<>();
+        if (scope == ResourceElementMatchingScope.SELF_OR_CHILD) {
             final boolean resourceEndsWithSep = resource.charAt(resource.length() - 1) == separatorChar;
 
             if (isSelfMatch) { // resource == path(curr)
@@ -671,14 +673,16 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
                     }
                 }
             }
+        } else if (scope == ResourceElementMatchingScope.SELF_OR_PREFIX) {
+            curr.collectChildEvaluators(resource, i, childEvalautors);
+        }
 
-            if (CollectionUtils.isNotEmpty(childEvalautors)) {
-                if (CollectionUtils.isNotEmpty(ret)) {
-                    childEvalautors.addAll(ret);
-                }
-
-                ret = childEvalautors;
+        if (CollectionUtils.isNotEmpty(childEvalautors)) {
+            if (CollectionUtils.isNotEmpty(ret)) {
+                childEvalautors.addAll(ret);
             }
+
+            ret = childEvalautors;
         }
 
         RangerPerfTracer.logAlways(perf);
@@ -731,7 +735,7 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
         return curr;
     }
 
-    private Set<T> getEvaluatorsForResources(Collection<String> resources, RangerAccessRequest.ResourceMatchingScope scope) {
+    private Set<T> getEvaluatorsForResources(Collection<String> resources, ResourceElementMatchingScope scope) {
         if(LOG.isDebugEnabled()) {
             LOG.debug("==> RangerResourceTrie.getEvaluatorsForResources(" + resources + ")");
         }
@@ -1228,6 +1232,64 @@ public class RangerResourceTrie<T extends RangerResourceEvaluator> {
             }
         }
 
+        void collectChildEvaluators(String resource, int startIndex, Set<U> childEvaluators) {
+            if (startIndex == resource.length()) {
+                collectChildEvaluators(childEvaluators);
+            } else if (startIndex < resource.length()) {
+                Character   startChar = getLookupChar(resource, startIndex);
+                TrieNode<U> childNode = children.get(startChar);
+
+                if (childNode != null) {
+                    if (!isOptimizedForSpace) {
+                        childNode.setupIfNeeded(childNode.getParent());
+                    }
+
+                    String childStr = childNode.getStr();
+                    int lenToMatch = Math.min(resource.length() - startIndex, childStr.length());
+
+                    if (resource.regionMatches(optIgnoreCase, startIndex, childStr, 0, lenToMatch)) {
+                        if (childNode.wildcardEvaluators != null) {
+                            childEvaluators.addAll(childNode.wildcardEvaluators);
+                        }
+
+                        if (childNode.evaluators != null) {
+                            childEvaluators.addAll(childNode.evaluators);
+                        }
+
+                        if (resource.length() == (startIndex + lenToMatch)) {
+                            childNode.collectChildEvaluators(childEvaluators);
+                        } else {
+                            childNode.children.values().stream().forEach(c -> c.collectChildEvaluators(resource, startIndex + childStr.length(), childEvaluators));
+                        }
+                    }
+                }
+            }
+        }
+
+        private void collectChildEvaluators(Set<U> childEvaluators) {
+            Stack<TrieNode<U>> nodes = new Stack<>();
+
+            nodes.addAll(children.values());
+
+            while (!nodes.isEmpty()) {
+                TrieNode<U> childNode = nodes.pop();
+
+                if (!isOptimizedForSpace) {
+                    childNode.setupIfNeeded(childNode.getParent());
+                }
+
+                if (childNode.wildcardEvaluators != null) {
+                    childEvaluators.addAll(childNode.wildcardEvaluators);
+                }
+
+                if (childNode.evaluators != null) {
+                    childEvaluators.addAll(childNode.evaluators);
+                }
+
+                nodes.addAll(childNode.children.values());
+            }
+        }
+
         private void removeEvaluatorFromSubtree(U evaluator) {
             if (CollectionUtils.isNotEmpty(wildcardEvaluators) && wildcardEvaluators.contains(evaluator)) {
                 undoSetup();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAuditPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAuditPolicyEvaluator.java
index 1c46f184c..ba24b8c3e 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAuditPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAuditPolicyEvaluator.java
@@ -129,7 +129,7 @@ public class RangerAuditPolicyEvaluator extends RangerDefaultPolicyEvaluator {
                     RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher();
 
                     if (resourceMatcher != null) {
-                        matchType = resourceMatcher.getMatchType(request.getResource(), request.getContext());
+                        matchType = resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext());
                     } else {
                         matchType = RangerPolicyResourceMatcher.MatchType.NONE;
                     }
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 eee1e1f1b..4ad2944a8 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
@@ -233,11 +233,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 							matchType = RangerPolicyResourceMatcher.MatchType.SELF;
 						}
 					} else {
-						if (request.getResourceMatchingScope() == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD) {
-							request.getContext().put(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING, RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD);
-						}
-						matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE;
-						request.getContext().remove(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING);
+						matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE;
 					}
 
 					final boolean isMatched;
@@ -473,7 +469,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 			if (RangerTagAccessRequest.class.isInstance(request)) {
 				matchType = ((RangerTagAccessRequest) request).getMatchType();
 			} else {
-				matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE;
+				matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE;
 			}
 
 			final boolean isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE;
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java
index e887730c9..f16157ce6 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.plugin.policyresourcematcher;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -33,6 +34,7 @@ import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyengine.RangerAccessResource;
 import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
 import org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher;
@@ -378,6 +380,11 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
 
     @Override
     public boolean isMatch(RangerPolicy policy, MatchScope scope, Map<String, Object> evalContext) {
+        return isMatch(policy, Collections.emptyMap(), scope, evalContext);
+    }
+
+    @Override
+    public boolean isMatch(RangerPolicy policy, Map<String, ResourceElementMatchingScope> scopes, MatchScope scope, Map<String, Object> evalContext) {
         boolean ret = false;
 
         RangerPerfTracer perf = null;
@@ -428,7 +435,7 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
                             for (String value : policyResource.getValues()) {
                                 accessResource.setValue(name, value);
 
-                                matchType = getMatchType(accessResource, evalContext);
+                                matchType = getMatchType(accessResource, scopes, evalContext);
 
                                 if (matchType != MatchType.NONE) { // One value for this resourceDef matched
                                     ret = true;
@@ -458,6 +465,11 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
 
     @Override
     public boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext) {
+        return isMatch(resource, Collections.emptyMap(), evalContext);
+    }
+
+    @Override
+    public boolean isMatch(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext) {
         RangerPerfTracer perf = null;
 
         if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_RESOURCE_MATCHER_MATCH_LOG)) {
@@ -487,7 +499,7 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
                 break;
             }
         }
-        final boolean ret = MapUtils.isNotEmpty(policyResources) && isMatch(policyResources, evalContext);
+        final boolean ret = MapUtils.isNotEmpty(policyResources) && isMatch(policyResources, scopes, evalContext);
 
         RangerPerfTracer.log(perf);
 
@@ -496,6 +508,11 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
 
     @Override
     public boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) {
+        return isMatch(resources, Collections.emptyMap(), evalContext);
+    }
+
+    @Override
+    public boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext) {
         if(LOG.isDebugEnabled()) {
             LOG.debug("==> RangerDefaultPolicyResourceMatcher.isMatch(" + resources  + ", " + evalContext + ")");
         }
@@ -524,7 +541,8 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
                     if (matcher != null) {
                         if (CollectionUtils.isNotEmpty(values)) {
                             for (String value : values) {
-                                ret = matcher.isMatch(value, evalContext);
+                                ret = matcher.isMatch(value, scopes.get(resourceName), evalContext);
+
                                 if (!ret) {
                                     break;
                                 }
@@ -558,12 +576,22 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
 
     @Override
     public boolean isMatch(RangerAccessResource resource, MatchScope scope, Map<String, Object> evalContext) {
-        MatchType matchType = getMatchType(resource, evalContext);
+        return isMatch(resource, Collections.emptyMap(), scope, evalContext);
+    }
+
+    @Override
+    public boolean isMatch(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, MatchScope scope, Map<String, Object> evalContext) {
+        MatchType matchType = getMatchType(resource, scopes, evalContext);
         return isMatch(scope, matchType);
     }
 
     @Override
     public MatchType getMatchType(RangerAccessResource resource, Map<String, Object> evalContext) {
+        return getMatchType(resource, Collections.emptyMap(), evalContext);
+    }
+
+    @Override
+    public MatchType getMatchType(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("==> RangerDefaultPolicyResourceMatcher.getMatchType(" + resource + evalContext + ")");
         }
@@ -582,6 +610,7 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
                 ret = MatchType.SELF;
             } else {
                 List<RangerResourceDef> hierarchy = getMatchingHierarchy(resource);
+
                 if (CollectionUtils.isNotEmpty(hierarchy)) {
 
                     int lastNonAnyMatcherIndex = -1;
@@ -610,7 +639,7 @@ public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceM
 
                         if (matcher != null) {
                             if (resourceValue != null || matcher.isMatchAny()) {
-                                if (matcher.isMatch(resourceValue, evalContext)) {
+                                if (matcher.isMatch(resourceValue, scopes.get(resourceDef.getName()), evalContext)) {
                                     ret = MatchType.SELF;
                                 } else {
                                     ret = MatchType.NONE;
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerPolicyResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerPolicyResourceMatcher.java
index 0220feba7..052e2df78 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerPolicyResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerPolicyResourceMatcher.java
@@ -25,6 +25,7 @@ import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyengine.RangerAccessResource;
 import org.apache.ranger.plugin.resourcematcher.RangerResourceMatcher;
 
@@ -50,14 +51,24 @@ public interface RangerPolicyResourceMatcher {
 
 	boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext);
 
+	boolean isMatch(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext);
+
 	boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext);
 
+	boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext);
+
 	boolean isMatch(RangerAccessResource resource, MatchScope scope, Map<String, Object> evalContext);
 
+	boolean isMatch(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, MatchScope scope, Map<String, Object> evalContext);
+
 	boolean isMatch(RangerPolicy policy, MatchScope scope, Map<String, Object> evalContext);
 
+	boolean isMatch(RangerPolicy policy, Map<String, ResourceElementMatchingScope> scopes, MatchScope scope, Map<String, Object> evalContext);
+
 	MatchType getMatchType(RangerAccessResource resource, Map<String, Object> evalContext);
 
+	MatchType getMatchType(RangerAccessResource resource, Map<String, ResourceElementMatchingScope> scopes, Map<String, Object> evalContext);
+
 	boolean isCompleteMatch(RangerAccessResource resource, Map<String, Object> evalContext);
 
 	boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext);
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
index 032d4487c..cb8d46adf 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java
@@ -390,9 +390,30 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat
 	}
 }
 
-final class CaseSensitiveStringMatcher extends ResourceMatcher {
-	CaseSensitiveStringMatcher(String value, Map<String, String> options) {
+abstract class AbstractStringResourceMatcher extends ResourceMatcher {
+	private final boolean isCaseSensitive;
+
+	protected AbstractStringResourceMatcher(String value, Map<String, String> options, boolean isCaseSensitive) {
 		super(value, options);
+
+		this.isCaseSensitive = isCaseSensitive;
+	}
+
+	@Override
+	public boolean isPrefixMatch(String resourceValue, Map<String, Object> evalContext) {
+		return isCaseSensitive ? StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
+				               : StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+	}
+
+	@Override
+	public boolean isChildMatch(String resourceValue, Map<String, Object> evalContext) {
+		return false; // child-match is applicable only for path resource
+	}
+}
+
+final class CaseSensitiveStringMatcher extends AbstractStringResourceMatcher {
+	CaseSensitiveStringMatcher(String value, Map<String, String> options) {
+		super(value, options, true);
 	}
 
 	@Override
@@ -402,8 +423,8 @@ final class CaseSensitiveStringMatcher extends ResourceMatcher {
 	int getPriority() { return 1 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0);}
 }
 
-final class CaseInsensitiveStringMatcher extends ResourceMatcher {
-	CaseInsensitiveStringMatcher(String value, Map<String, String> options) { super(value, options); }
+final class CaseInsensitiveStringMatcher extends AbstractStringResourceMatcher {
+	CaseInsensitiveStringMatcher(String value, Map<String, String> options) { super(value, options, false); }
 
 	@Override
 	boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
@@ -412,11 +433,11 @@ final class CaseInsensitiveStringMatcher extends ResourceMatcher {
 	int getPriority() {return 2 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class QuotedCaseSensitiveStringMatcher extends ResourceMatcher {
+final class QuotedCaseSensitiveStringMatcher extends AbstractStringResourceMatcher {
 	private final String quoteChars;
 
 	QuotedCaseSensitiveStringMatcher(String value, Map<String, String> options, String quoteChars) {
-		super(value, options);
+		super(value, options, true);
 
 		this.quoteChars = quoteChars;
 	}
@@ -433,9 +454,9 @@ final class QuotedCaseSensitiveStringMatcher extends ResourceMatcher {
 	int getPriority() {return 2 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class CaseSensitiveStartsWithMatcher extends ResourceMatcher {
+final class CaseSensitiveStartsWithMatcher extends AbstractStringResourceMatcher {
 	CaseSensitiveStartsWithMatcher(String value, Map<String, String> options) {
-		super(value, options);
+		super(value, options, true);
 	}
 
 	@Override
@@ -445,8 +466,8 @@ final class CaseSensitiveStartsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 3 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0);}
 }
 
-final class CaseInsensitiveStartsWithMatcher extends ResourceMatcher {
-	CaseInsensitiveStartsWithMatcher(String value, Map<String, String> options) { super(value, options); }
+final class CaseInsensitiveStartsWithMatcher extends AbstractStringResourceMatcher {
+	CaseInsensitiveStartsWithMatcher(String value, Map<String, String> options) { super(value, options, false); }
 
 	@Override
 	boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
@@ -455,11 +476,11 @@ final class CaseInsensitiveStartsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 4 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class QuotedCaseSensitiveStartsWithMatcher extends ResourceMatcher {
+final class QuotedCaseSensitiveStartsWithMatcher extends AbstractStringResourceMatcher {
 	private final String quoteChars;
 
 	QuotedCaseSensitiveStartsWithMatcher(String value, Map<String, String> options, String quoteChars) {
-		super(value, options);
+		super(value, options, true);
 
 		this.quoteChars = quoteChars;
 	}
@@ -476,9 +497,9 @@ final class QuotedCaseSensitiveStartsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 4 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class CaseSensitiveEndsWithMatcher extends ResourceMatcher {
+final class CaseSensitiveEndsWithMatcher extends AbstractStringResourceMatcher {
 	CaseSensitiveEndsWithMatcher(String value, Map<String, String> options) {
-		super(value, options);
+		super(value, options, true);
 	}
 
 	@Override
@@ -488,9 +509,9 @@ final class CaseSensitiveEndsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 3 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class CaseInsensitiveEndsWithMatcher extends ResourceMatcher {
+final class CaseInsensitiveEndsWithMatcher extends AbstractStringResourceMatcher {
 	CaseInsensitiveEndsWithMatcher(String value, Map<String, String> options) {
-		super(value, options);
+		super(value, options, false);
 	}
 
 	@Override
@@ -500,11 +521,11 @@ final class CaseInsensitiveEndsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 4 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class QuotedCaseSensitiveEndsWithMatcher extends ResourceMatcher {
+final class QuotedCaseSensitiveEndsWithMatcher extends AbstractStringResourceMatcher {
 	private final String quoteChars;
 
 	QuotedCaseSensitiveEndsWithMatcher(String value, Map<String, String> options, String quoteChars) {
-		super(value, options);
+		super(value, options, true);
 
 		this.quoteChars = quoteChars;
 	}
@@ -521,9 +542,9 @@ final class QuotedCaseSensitiveEndsWithMatcher extends ResourceMatcher {
 	int getPriority() { return 4 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class CaseSensitiveWildcardMatcher extends ResourceMatcher {
+final class CaseSensitiveWildcardMatcher extends AbstractStringResourceMatcher {
 	CaseSensitiveWildcardMatcher(String value, Map<String, String> options) {
-		super(value, options);
+		super(value, options, true);
 	}
 
 	@Override
@@ -534,9 +555,9 @@ final class CaseSensitiveWildcardMatcher extends ResourceMatcher {
 }
 
 
-final class CaseInsensitiveWildcardMatcher extends ResourceMatcher {
+final class CaseInsensitiveWildcardMatcher extends AbstractStringResourceMatcher {
 	CaseInsensitiveWildcardMatcher(String value, Map<String, String> options) {
-		super(value, options);
+		super(value, options, false);
 	}
 
 	@Override
@@ -546,11 +567,11 @@ final class CaseInsensitiveWildcardMatcher extends ResourceMatcher {
 	int getPriority() {return 6 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0); }
 }
 
-final class QuotedCaseSensitiveWildcardMatcher extends ResourceMatcher {
+final class QuotedCaseSensitiveWildcardMatcher extends AbstractStringResourceMatcher {
 	private final String quoteChars;
 
 	QuotedCaseSensitiveWildcardMatcher(String value, Map<String, String> options, String quoteChars) {
-		super(value, options);
+		super(value, options, true);
 
 		this.quoteChars = quoteChars;
 	}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
index c421388e7..702cb272f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.plugin.resourcematcher;
 
 
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,38 +32,45 @@ public class RangerDefaultResourceMatcher extends RangerAbstractResourceMatcher
 	private static final Logger LOG = LoggerFactory.getLogger(RangerDefaultResourceMatcher.class);
 
 	@Override
-	public boolean isMatch(Object resource, Map<String, Object> evalContext) {
+	public boolean isMatch(Object resource, ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
 		if(LOG.isDebugEnabled()) {
 			LOG.debug("==> RangerDefaultResourceMatcher.isMatch(" + resource + ", " + evalContext + ")");
 		}
 
 		boolean ret = false;
 		boolean allValuesRequested = isAllValuesRequested(resource);
+		boolean isPrefixMatch = matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX;
 
-		if(allValuesRequested || isMatchAny) {
+		if (isMatchAny || (allValuesRequested && !isPrefixMatch)) {
 			ret = isMatchAny;
 		} else {
 			if (resource instanceof String) {
 				String strValue = (String) resource;
 
 				for (ResourceMatcher resourceMatcher : resourceMatchers.getResourceMatchers()) {
-					ret = resourceMatcher.isMatch(strValue, evalContext);
+					ret = resourceMatcher.isMatch(strValue, matchingScope, evalContext);
+
 					if (ret) {
 						break;
 					}
 				}
 			} else if (resource instanceof Collection) {
 				@SuppressWarnings("unchecked")
-				Collection<String> collValue = (Collection<String>) resource;
+				Collection<String> resourceValues = (Collection<String>) resource;
 
 				for (ResourceMatcher resourceMatcher : resourceMatchers.getResourceMatchers()) {
-					ret = resourceMatcher.isMatchAny(collValue, evalContext);
+					for (String resourceValue : resourceValues) {
+						ret = resourceMatcher.isMatch(resourceValue, matchingScope, evalContext);
+
+						if (ret) {
+							break;
+						}
+					}
 					if (ret) {
 						break;
 					}
 				}
 			}
-
 		}
 
 		ret = applyExcludes(allValuesRequested, ret);
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
index 5fa5b68d4..1af967fbd 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java
@@ -20,7 +20,6 @@
 package org.apache.ranger.plugin.resourcematcher;
 
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.MapUtils;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOCase;
 import org.apache.commons.lang.ArrayUtils;
@@ -261,15 +260,15 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
 		if (needWildcardMatch) { // test?, test*a*, test*a*b, *test*a
 			ret = new WildcardResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
 		} else if (wildcardStartIdx == -1) { // test, testa, testab
-			ret = new StringResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? 2 : 1);
+			ret = new PathResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::equalsIgnoreCase : StringUtils::equals, optIgnoreCase ? 2 : 1, !optIgnoreCase);
 		} else if (wildcardStartIdx == 0) { // *test, **test, *testa, *testab
 			String matchStr = policyValue.substring(wildcardEndIdx + 1);
-			ret = new StringResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::endsWithIgnoreCase : StringUtils::endsWith, optIgnoreCase ? 4 : 3);
+			ret = new PathResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::endsWithIgnoreCase : StringUtils::endsWith, optIgnoreCase ? 4 : 3, !optIgnoreCase);
 		} else if (wildcardEndIdx != (len - 1)) { // test*a, test*ab
 			ret = new WildcardResourceMatcher(policyValue, getOptions(), pathSeparatorChar, optIgnoreCase, FilenameUtils::wildcardMatch, 6);
 		} else { // test*, test**, testa*, testab*
 			String matchStr = policyValue.substring(0, wildcardStartIdx);
-			ret = new StringResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 4 : 3);
+			ret = new PathResourceMatcher(matchStr, getOptions(), pathSeparatorChar, optIgnoreCase ? StringUtils::startsWithIgnoreCase : StringUtils::startsWith, optIgnoreCase ? 4 : 3, !optIgnoreCase);
 		}
 
 		if (optReplaceTokens) {
@@ -291,99 +290,132 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
 		R apply(T t, U u, V v, W w, X x);
 	}
 
-	static abstract class PathResourceMatcher extends ResourceMatcher {
+	static abstract class AbstractPathResourceMatcher extends ResourceMatcher {
 		final char    pathSeparatorChar;
 		final int     priority;
+		final boolean isCaseSensitive;
 
-		PathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, int priority) {
+		AbstractPathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, int priority, boolean isCaseSensitive) {
 			super(value, options);
-			this.pathSeparatorChar    = pathSeparatorChar;
-			this.priority             = priority;
+
+			this.pathSeparatorChar = pathSeparatorChar;
+			this.priority          = priority;
+			this.isCaseSensitive   = isCaseSensitive;
 		}
 		int getPriority() {
 			return priority + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0);
 		}
+
+		@Override
+		public boolean isPrefixMatch(String resourceValue, Map<String, Object> evalContext) {
+			return isCaseSensitive ? StringUtils.startsWith(getExpandedValue(evalContext), resourceValue)
+			                       : StringUtils.startsWithIgnoreCase(getExpandedValue(evalContext), resourceValue);
+		}
 	}
 
-	static class StringResourceMatcher extends PathResourceMatcher {
+	static class PathResourceMatcher extends AbstractPathResourceMatcher {
 		final BiFunction<String, String, Boolean> function;
-		StringResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, BiFunction<String, String, Boolean> function, int priority) {
-			super(value, options, pathSeparatorChar, priority);
+
+		PathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, BiFunction<String, String, Boolean> function, int priority, boolean isCaseSensitive) {
+			super(value, options, pathSeparatorChar, priority, isCaseSensitive);
+
 			this.function = function;
 		}
+
 		@Override
 		boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
 			if (LOG.isDebugEnabled()) {
-				LOG.debug("==> StringResourceMatcher.isMatch(resourceValue=" + resourceValue + ", evalContext=" + evalContext + ")");
-			}
-			String expandedValue = getExpandedValue(evalContext);
-			boolean ret = function.apply(resourceValue, expandedValue);
-			if (!ret) {
-				RangerAccessRequest.ResourceMatchingScope scope = MapUtils.isNotEmpty(evalContext) ? (RangerAccessRequest.ResourceMatchingScope) evalContext.get(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING) : null;
-				if (scope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD) {
-					int lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
-					if (lastLevelSeparatorIndex != -1) {
-						String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
-						if (resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
-							resourceValue = resourceValue.substring(0, resourceValue.length()-1);
-						}
-						ret = function.apply(resourceValue, shorterExpandedValue);
-					}
-				}
+				LOG.debug("==> PathResourceMatcher.isMatch(resourceValue=" + resourceValue + ", evalContext=" + evalContext + ")");
 			}
+
+			String  expandedValue = getExpandedValue(evalContext);
+			boolean ret           = function.apply(resourceValue, expandedValue);
+
 			if (LOG.isDebugEnabled()) {
-				LOG.debug("<== StringResourceMatcher.isMatch(resourceValue=" + resourceValue + ", expandedValue=" + expandedValue + ") : result:[" + ret + "]");
+				LOG.debug("<== PathResourceMatcher.isMatch(resourceValue=" + resourceValue + ", expandedValue=" + expandedValue + ") : result:[" + ret + "]");
 			}
+
+			return ret;
+		}
+
+		@Override
+		public boolean isChildMatch(String resourceValue, Map<String, Object> evalContext) {
+			boolean ret                     = false;
+			String  expandedValue           = getExpandedValue(evalContext);
+			int     lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
+
+			if (lastLevelSeparatorIndex != -1) {
+				String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
+
+				if (resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
+					resourceValue = resourceValue.substring(0, resourceValue.length()-1);
+				}
+
+				ret = function.apply(resourceValue, shorterExpandedValue);
+			}
+
 			return ret;
 		}
 
 	}
 
-	static class WildcardResourceMatcher extends PathResourceMatcher {
+	static class WildcardResourceMatcher extends AbstractPathResourceMatcher {
 		final TriFunction<String, String, IOCase, Boolean> function;
-		final IOCase ioCase;
+		final IOCase                                       ioCase;
 
 		WildcardResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, boolean optIgnoreCase, TriFunction<String, String, IOCase, Boolean> function, int priority) {
-			super(value, options, pathSeparatorChar, priority);
+			super(value, options, pathSeparatorChar, priority, !optIgnoreCase);
+
 			this.function = function;
 			this.ioCase   = optIgnoreCase ? IOCase.INSENSITIVE : IOCase.SENSITIVE;
 		}
+
 		@Override
 		boolean isMatch(String resourceValue, Map<String, Object> evalContext) {
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("==> WildcardResourceMatcher.isMatch(resourceValue=" + resourceValue + ", evalContext=" + evalContext + ")");
 			}
-			String expandedValue = getExpandedValue(evalContext);
-			boolean ret = function.apply(resourceValue, expandedValue, ioCase);
-			if (!ret) {
-				RangerAccessRequest.ResourceMatchingScope scope = MapUtils.isNotEmpty(evalContext) ? (RangerAccessRequest.ResourceMatchingScope) evalContext.get(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING) : null;
-				if (scope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD) {
-					int lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
-					if (lastLevelSeparatorIndex != -1) {
-						String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
-						if (resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
-							resourceValue = resourceValue.substring(0, resourceValue.length()-1);
-						}
-						ret = function.apply(resourceValue, shorterExpandedValue, ioCase);
-					}
-				}
-			}
+
+			String  expandedValue = getExpandedValue(evalContext);
+			boolean ret           = function.apply(resourceValue, expandedValue, ioCase);
+
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("<== WildcardResourceMatcher.isMatch(resourceValue=" + resourceValue + ", expandedValue=" + expandedValue + ") : result:[" + ret + "]");
 			}
 			return ret;
 		}
+
+		@Override
+		public boolean isChildMatch(String resourceValue, Map<String, Object> evalContext) {
+			boolean ret                     = false;
+			String  expandedValue           = getExpandedValue(evalContext);
+			int     lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
+
+			if (lastLevelSeparatorIndex != -1) {
+				String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
+
+				if (resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
+					resourceValue = resourceValue.substring(0, resourceValue.length()-1);
+				}
+
+				ret = function.apply(resourceValue, shorterExpandedValue, ioCase);
+			}
+
+			return ret;
+		}
 	}
 
-	static class RecursiveWildcardResourceMatcher extends PathResourceMatcher {
+	static class RecursiveWildcardResourceMatcher extends AbstractPathResourceMatcher {
 		final QuintFunction<String, String, Character, IOCase, Boolean, String[]> function;
 		final IOCase ioCase;
 		String[] wildcardPathElements;
 
 		RecursiveWildcardResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, boolean optIgnoreCase, QuintFunction<String, String, Character, IOCase, Boolean, String[]> function, int priority) {
-			super(value, options, pathSeparatorChar, priority);
+			super(value, options, pathSeparatorChar, priority, !optIgnoreCase);
+
 			this.function = function;
 			this.ioCase   = optIgnoreCase ? IOCase.INSENSITIVE : IOCase.SENSITIVE;
+
 			if (!getNeedsDynamicEval()) {
 				wildcardPathElements = StringUtils.split(value, pathSeparatorChar);
 			}
@@ -402,28 +434,36 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
 			}
 
 			boolean ret = function.apply(resourceValue, expandedValue, pathSeparatorChar, ioCase, wildcardPathElements);
-			if (!ret) {
-				RangerAccessRequest.ResourceMatchingScope scope = MapUtils.isNotEmpty(evalContext) ? (RangerAccessRequest.ResourceMatchingScope) evalContext.get(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING) : null;
-				if (scope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD) {
-					int lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
-					if (lastLevelSeparatorIndex != -1) {
-						String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
-						if (resourceValue.charAt(resourceValue.length()-1) == pathSeparatorChar) {
-							resourceValue = resourceValue.substring(0, resourceValue.length()-1);
-						}
-						String[] shorterWildCardPathElements = StringUtils.split(shorterExpandedValue, pathSeparatorChar);
-						ret = function.apply(resourceValue, shorterExpandedValue, pathSeparatorChar, ioCase, shorterWildCardPathElements);
-					}
-				}
-			}
+
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("<== RecursiveWildcardResourceMatcher.isMatch(resourceValue=" + resourceValue + ", expandedValue=" + expandedValue + ") : result:[" + ret + "]");
 			}
 			return ret;
 		}
+
+		@Override
+		public boolean isChildMatch(String resourceValue, Map<String, Object> evalContext) {
+			boolean ret = false;
+			String expandedValue = getExpandedValue(evalContext);
+			int lastLevelSeparatorIndex = expandedValue.lastIndexOf(pathSeparatorChar);
+
+			if (lastLevelSeparatorIndex != -1) {
+				String shorterExpandedValue = expandedValue.substring(0, lastLevelSeparatorIndex);
+
+				if (resourceValue.charAt(resourceValue.length() - 1) == pathSeparatorChar) {
+					resourceValue = resourceValue.substring(0, resourceValue.length() - 1);
+				}
+
+				String[] shorterWildCardPathElements = StringUtils.split(shorterExpandedValue, pathSeparatorChar);
+
+				ret = function.apply(resourceValue, shorterExpandedValue, pathSeparatorChar, ioCase, shorterWildCardPathElements);
+			}
+
+			return ret;
+		}
 	}
 
-	static class RecursivePathResourceMatcher extends PathResourceMatcher {
+	static class RecursivePathResourceMatcher extends AbstractPathResourceMatcher {
 		String valueWithoutSeparator;
 		String valueWithSeparator;
 
@@ -431,7 +471,8 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
 		final BiFunction<String, String, Boolean> fallbackFunction;
 
 		RecursivePathResourceMatcher(String value, Map<String, String> options, char pathSeparatorChar, BiFunction<String, String, Boolean> primaryFunction, BiFunction<String, String, Boolean> fallbackFunction, int priority) {
-			super(value, options, pathSeparatorChar, priority);
+			super(value, options, pathSeparatorChar, priority, true);
+
 			this.primaryFunction    = primaryFunction;
 			this.fallbackFunction   = fallbackFunction;
 		}
@@ -465,28 +506,44 @@ public class RangerPathResourceMatcher extends RangerDefaultResourceMatcher {
 
 			if (!ret && noSeparator != null) {
 				final String withSeparator = getNeedsDynamicEval() ? noSeparator + pathSeparatorChar : valueWithSeparator;
-				ret = fallbackFunction.apply(resourceValue, withSeparator);
 
-				if (!ret) {
-					RangerAccessRequest.ResourceMatchingScope scope = MapUtils.isNotEmpty(evalContext) ? (RangerAccessRequest.ResourceMatchingScope) evalContext.get(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING) : null;
-					if (scope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD) {
-						final int lastLevelSeparatorIndex = noSeparator.lastIndexOf(pathSeparatorChar);
-						if (lastLevelSeparatorIndex != -1) {
-							final String shorterExpandedValue = noSeparator.substring(0, lastLevelSeparatorIndex);
-							if (resourceValue.charAt(resourceValue.length() - 1) == pathSeparatorChar) {
-								resourceValue = resourceValue.substring(0, resourceValue.length() - 1);
-							}
-							ret = primaryFunction.apply(resourceValue, shorterExpandedValue);
-						}
-					}
-				}
+				ret = fallbackFunction.apply(resourceValue, withSeparator);
 			}
+
 			if (LOG.isDebugEnabled()) {
 				LOG.debug("<== RecursivePathResourceMatcher.isMatch(resourceValue=" + resourceValue + ", expandedValueWithoutTrailingSeparatorChar=" + noSeparator + ") : result:[" + ret + "]");
 			}
 
 			return ret;
 		}
-	}
 
+		@Override
+		public boolean isChildMatch(String resourceValue, Map<String, Object> evalContext) {
+			boolean ret = false;
+			final String noSeparator;
+			if (getNeedsDynamicEval()) {
+				String expandedPolicyValue = getExpandedValue(evalContext);
+				noSeparator = expandedPolicyValue != null ? getStringToCompare(expandedPolicyValue) : null;
+			} else {
+				if (valueWithoutSeparator == null && value != null) {
+					valueWithoutSeparator = getStringToCompare(value);
+					valueWithSeparator = valueWithoutSeparator + pathSeparatorChar;
+				}
+				noSeparator = valueWithoutSeparator;
+			}
+			final int lastLevelSeparatorIndex = noSeparator.lastIndexOf(pathSeparatorChar);
+
+			if (lastLevelSeparatorIndex != -1) {
+				final String shorterExpandedValue = noSeparator.substring(0, lastLevelSeparatorIndex);
+
+				if (resourceValue.charAt(resourceValue.length() - 1) == pathSeparatorChar) {
+					resourceValue = resourceValue.substring(0, resourceValue.length() - 1);
+				}
+
+				ret = primaryFunction.apply(resourceValue, shorterExpandedValue);
+			}
+
+			return ret;
+		}
+	}
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
index 0cb3e0fed..c4ce30d36 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java
@@ -21,6 +21,7 @@ package org.apache.ranger.plugin.resourcematcher;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 
 import java.util.Map;
 
@@ -33,7 +34,7 @@ public interface RangerResourceMatcher {
 
 	boolean isMatchAny();
 
-	boolean isMatch(Object resource, Map<String, Object> evalContext);
+	boolean isMatch(Object resource, ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext);
 
 	boolean isCompleteMatch(String resource, Map<String, Object> evalContext);
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
index ee2fff3ed..ce73b3006 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcher.java
@@ -234,10 +234,10 @@ public class RangerURLResourceMatcher extends RangerDefaultResourceMatcher {
     }
 }
 
-final class CaseSensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
+final class CaseSensitiveURLRecursiveWildcardMatcher extends AbstractStringResourceMatcher {
     private final char levelSeparatorChar;
     CaseSensitiveURLRecursiveWildcardMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
-        super(value, options);
+        super(value, options, true);
         this.levelSeparatorChar = levelSeparatorChar;
     }
 
@@ -248,10 +248,10 @@ final class CaseSensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
     int getPriority() { return 7 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0);}
 }
 
-final class CaseInsensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
+final class CaseInsensitiveURLRecursiveWildcardMatcher extends AbstractStringResourceMatcher {
     private final char levelSeparatorChar;
     CaseInsensitiveURLRecursiveWildcardMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
-        super(value, options);
+        super(value, options, false);
         this.levelSeparatorChar = levelSeparatorChar;
     }
 
@@ -263,13 +263,13 @@ final class CaseInsensitiveURLRecursiveWildcardMatcher extends ResourceMatcher {
 
 }
 
-abstract class RecursiveMatcher extends ResourceMatcher {
+abstract class RecursiveMatcher extends AbstractStringResourceMatcher {
     final char levelSeparatorChar;
     String valueWithoutSeparator;
     String valueWithSeparator;
 
-    RecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
-        super(value, options);
+    RecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar, boolean isCaseSensitive) {
+        super(value, options, isCaseSensitive);
         this.levelSeparatorChar = levelSeparatorChar;
     }
 
@@ -284,7 +284,7 @@ abstract class RecursiveMatcher extends ResourceMatcher {
 
 final class CaseSensitiveURLRecursiveMatcher extends RecursiveMatcher {
     CaseSensitiveURLRecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
-        super(value, options, levelSeparatorChar);
+        super(value, options, levelSeparatorChar, true);
     }
 
     @Override
@@ -316,7 +316,7 @@ final class CaseSensitiveURLRecursiveMatcher extends RecursiveMatcher {
 
 final class CaseInsensitiveURLRecursiveMatcher extends RecursiveMatcher {
     CaseInsensitiveURLRecursiveMatcher(String value, Map<String, String> options, char levelSeparatorChar) {
-        super(value, options, levelSeparatorChar);
+        super(value, options, levelSeparatorChar, false);
     }
 
     @Override
@@ -345,4 +345,4 @@ final class CaseInsensitiveURLRecursiveMatcher extends RecursiveMatcher {
     }
 
     int getPriority() { return 8 + (getNeedsDynamicEval() ? DYNAMIC_EVALUATION_PENALTY : 0);}
-}
\ No newline at end of file
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
index 5df4f1e3a..ad0942fbe 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java
@@ -21,6 +21,8 @@ package org.apache.ranger.plugin.resourcematcher;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchType;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerRequestExprResolver;
 import org.apache.ranger.plugin.util.StringTokenReplacer;
@@ -28,7 +30,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.Serializable;
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.Map;
 
@@ -52,24 +53,54 @@ abstract class ResourceMatcher {
     }
 
     abstract boolean isMatch(String resourceValue, Map<String, Object> evalContext);
-    abstract int getPriority();
 
-    boolean isMatchAny() { return value != null && value.length() == 0; }
+    abstract boolean isPrefixMatch(String resourceValue, Map<String, Object> evalContext);
 
-    boolean getNeedsDynamicEval() {
-        return exprResolver != null || tokenReplacer != null;
+    abstract boolean isChildMatch(String resourceValue, Map<String, Object> evalContext);
+
+    final boolean isMatch(String resourceValue, ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
+        final ResourceElementMatchType matchType = getMatchType(resourceValue, matchingScope, evalContext);
+        final boolean                  ret;
+
+        if (matchType == ResourceElementMatchType.SELF) {
+            ret = true;
+        } else if (matchType == ResourceElementMatchType.PREFIX) {
+            ret = matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX;
+        } else if (matchType == ResourceElementMatchType.CHILD) {
+            ret = matchingScope == ResourceElementMatchingScope.SELF_OR_CHILD;
+        } else {
+            ret = false;
+        }
+
+        return ret;
     }
 
-    public boolean isMatchAny(Collection<String> resourceValues, Map<String, Object> evalContext) {
-        if (resourceValues != null) {
-            for (String resourceValue : resourceValues) {
-                if (isMatch(resourceValue, evalContext)) {
-                    return true;
+    final ResourceElementMatchType getMatchType(String resourceValue, ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
+        ResourceElementMatchType ret = ResourceElementMatchType.NONE;
+
+        if (isMatch(resourceValue, evalContext)) {
+            ret = ResourceElementMatchType.SELF;
+        } else {
+            if (matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX) {
+                if (isPrefixMatch(resourceValue, evalContext)) {
+                    ret = ResourceElementMatchType.PREFIX;
+                }
+            } else if (matchingScope == ResourceElementMatchingScope.SELF_OR_CHILD) {
+                if (isChildMatch(resourceValue, evalContext)) {
+                    ret = ResourceElementMatchType.CHILD;
                 }
             }
         }
 
-        return false;
+        return ret;
+    }
+
+    abstract int getPriority();
+
+    boolean isMatchAny() { return value != null && value.length() == 0; }
+
+    boolean getNeedsDynamicEval() {
+        return exprResolver != null || tokenReplacer != null;
     }
 
     @Override
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
index e60fe055b..2ba8135b1 100644
--- 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
@@ -21,7 +21,7 @@ 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.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyengine.RangerResourceTrie;
 import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
 import org.slf4j.Logger;
@@ -39,15 +39,19 @@ 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);
+        return getEvaluators(resourceTrie, resource, null);
     }
 
-    public static <T  extends RangerResourceEvaluator> Collection<T> getEvaluators(Map<String, RangerResourceTrie<T>> resourceTrie, Map<String, ?> resource, RangerAccessRequest.ResourceMatchingScope scope) {
+    public static <T  extends RangerResourceEvaluator> Collection<T> getEvaluators(Map<String, RangerResourceTrie<T>> resourceTrie, Map<String, ?> resource, Map<String, ResourceElementMatchingScope> scopes) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("==> RangerPolicyResourceEvaluatorsRetriever.getEvaluators(" + resource + ")");
         }
         Set<T> ret = null;
 
+        if (scopes == null) {
+            scopes = Collections.emptyMap();
+        }
+
         if (MapUtils.isNotEmpty(resourceTrie) && MapUtils.isNotEmpty(resource)) {
             Set<String> resourceKeys = resource.keySet();
 
@@ -63,7 +67,7 @@ public class RangerResourceEvaluatorsRetriever {
                 Object resourceValues = resource.get(resourceDefName);
 
                 Set<T> inheritedMatchers   = trie.getInheritedEvaluators();
-                Set<T> matchersForResource = trie.getEvaluatorsForResource(resourceValues, scope);
+                Set<T> matchersForResource = trie.getEvaluatorsForResource(resourceValues, scopes.get(resourceDefName));
 
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("ResourceDefName:[" + resourceDefName + "], values:[" + resourceValues + "], resource-matchers:[" + matchersForResource + "], inherited-matchers:[" + inheritedMatchers + "]");
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPathResourceTrie.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPathResourceTrie.java
index 30a7215a6..d23509f86 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPathResourceTrie.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPathResourceTrie.java
@@ -21,6 +21,7 @@ package org.apache.ranger.plugin.policyengine;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
 import org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher;
@@ -71,7 +72,7 @@ public class TestPathResourceTrie {
 
 	@Test
 	public void testChildrenScope() {
-		final RangerAccessRequest.ResourceMatchingScope scope = RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD;
+		final ResourceElementMatchingScope scope = ResourceElementMatchingScope.SELF_OR_CHILD;
 
 		verifyEvaluators("/", scope, EVAL_, EVAL_nr, EVAL_HOME, EVAL_HOME_, EVAL_TMPnr, EVAL_TMP_nr, EVAL_TMPFILE, EVAL_TMPdTXT);
 		verifyEvaluators("/tmp", scope, EVAL_, EVAL_TMPnr, EVAL_TMP_nr, EVAL_TMP_AB);
@@ -84,9 +85,24 @@ public class TestPathResourceTrie {
 		verifyEvaluators("invalid: does-not-begin-with-sep", scope);
 	}
 
+	@Test
+	public void testPrefixScope() {
+		final ResourceElementMatchingScope scope = ResourceElementMatchingScope.SELF_OR_PREFIX;
+
+		verifyEvaluators("/", scope, EVAL_, EVAL_nr, EVAL_HOME, EVAL_HOME_, EVAL_TMPnr, EVAL_TMP_nr, EVAL_TMP_AB, EVAL_TMP_A_B, EVAL_TMP_AC_D_E_F, EVAL_TMPFILE, EVAL_TMPdTXT, EVAL_TMPA_B);
+		verifyEvaluators("/tmp", scope, EVAL_, EVAL_TMPnr, EVAL_TMP_nr, EVAL_TMP_AB, EVAL_TMP_A_B, EVAL_TMP_AC_D_E_F, EVAL_TMPFILE, EVAL_TMPdTXT, EVAL_TMPA_B);
+		verifyEvaluators("/tmp/", scope, EVAL_, EVAL_TMP_nr, EVAL_TMP_AB, EVAL_TMP_A_B, EVAL_TMP_AC_D_E_F);
+		verifyEvaluators("/tmp/a", scope, EVAL_, EVAL_TMP_AB, EVAL_TMP_A_B, EVAL_TMP_AC_D_E_F);
+		verifyEvaluators("/tmp/ac", scope, EVAL_, EVAL_TMP_AC_D_E_F);
+		verifyEvaluators("/tmp/ac/d", scope, EVAL_, EVAL_TMP_AC_D_E_F);
+		verifyEvaluators("/tmp/ac/d/e", scope, EVAL_, EVAL_TMP_AC_D_E_F);
+		verifyEvaluators("/unmatched", scope, EVAL_);
+		verifyEvaluators("invalid: does-not-begin-with-sep", scope);
+	}
+
 	@Test
 	public void testSelfScope() {
-		final RangerAccessRequest.ResourceMatchingScope scope = RangerAccessRequest.ResourceMatchingScope.SELF;
+		final ResourceElementMatchingScope scope = ResourceElementMatchingScope.SELF;
 
 		verifyEvaluators("/", scope, EVAL_, EVAL_nr);
 		verifyEvaluators("/tmp", scope, EVAL_, EVAL_TMPnr);
@@ -99,7 +115,7 @@ public class TestPathResourceTrie {
 		verifyEvaluators("invalid: does-not-begin-with-sep", scope);
 	}
 
-	private void verifyEvaluators(String resource, RangerAccessRequest.ResourceMatchingScope scope, RangerResourceEvaluator... evaluators) {
+	private void verifyEvaluators(String resource, ResourceElementMatchingScope scope, RangerResourceEvaluator... evaluators) {
 		Set<RangerResourceEvaluator> expected = evaluators.length == 0 ? null : new HashSet<>(Arrays.asList(evaluators));
 		Set<RangerResourceEvaluator> result   = trie.getEvaluatorsForResource(resource, scope);
 
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 b2a5151e5..6a3875ad5 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
@@ -482,6 +482,20 @@ public class TestPolicyEngine {
 		runTestsFromResourceFiles(resourceFiles);
 	}
 
+	@Test
+	public void testAnyResourceAccess_Kafka() throws Exception {
+		String[] resourceFiles = {"/policyengine/test_policyengine_kafka.json"};
+
+		runTestsFromResourceFiles(resourceFiles);
+	}
+
+	@Test
+	public void testAnyResourceAccess_S3() throws Exception {
+		String[] resourceFiles = {"/policyengine/test_policyengine_aws_s3.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/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
index e31437fc1..767795e81 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcherTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.ranger.plugin.resourcematcher;
 
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.junit.Test;
 
 import java.util.Map;
@@ -42,7 +43,7 @@ public class RangerAbstractResourceMatcherTest {
     static class AbstractMatcherWrapper extends RangerAbstractResourceMatcher {
 
         @Override
-        public boolean isMatch(Object resource, Map<String, Object> evalContext) {
+        public boolean isMatch(Object resource, ResourceElementMatchingScope matchingScope, Map<String, Object> evalContext) {
             fail("This method is not expected to be used by test!");
             return false;
         }
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
index ad21b3239..e00bc834d 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcherTest.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.resourcematcher;
 import com.google.common.collect.Lists;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.junit.Test;
 
@@ -59,7 +60,7 @@ public class RangerDefaultResourceMatcherTest {
             RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, excludes);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource, evalContext));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, ResourceElementMatchingScope.SELF, evalContext));
         }
     }
 
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
index 8fe3be9cc..5e8efb720 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcherTest.java
@@ -22,7 +22,7 @@ package org.apache.ranger.plugin.resourcematcher;
 import com.google.common.collect.Lists;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
-import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.junit.Test;
 
@@ -100,7 +100,7 @@ public class RangerPathResourceMatcherTest {
             RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, optWildcard, isRecursive);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource, evalContext));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, ResourceElementMatchingScope.SELF, evalContext));
         }
     }
 
@@ -116,10 +116,9 @@ public class RangerPathResourceMatcherTest {
 
             Map<String, Object> evalContext = new HashMap<>();
             RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
-            evalContext.put(RangerAccessRequest.RANGER_ACCESS_REQUEST_SCOPE_STRING, RangerAccessRequest.ResourceMatchingScope.SELF_OR_CHILD);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, optWildcard, isRecursive);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource, evalContext));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, ResourceElementMatchingScope.SELF_OR_CHILD, evalContext));
         }
     }
 
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
index 2b7f27200..904cb61b2 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/RangerURLResourceMatcherTest.java
@@ -22,6 +22,7 @@ package org.apache.ranger.plugin.resourcematcher;
 import com.google.common.collect.Lists;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.junit.Test;
 
@@ -66,7 +67,7 @@ public class RangerURLResourceMatcherTest {
             RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
             MatcherWrapper matcher = new MatcherWrapper(policyValue, optWildcard, isRecursive);
-            assertEquals(getMessage(row), result, matcher.isMatch(resource, evalContext));
+            assertEquals(getMessage(row), result, matcher.isMatch(resource, ResourceElementMatchingScope.SELF, evalContext));
         }
     }
 
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
index ea7bc01f2..ef8ee6c32 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/resourcematcher/TestResourceMatcher.java
@@ -28,6 +28,7 @@ import java.util.Map;
 
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
 import org.apache.ranger.plugin.resourcematcher.TestResourceMatcher.ResourceMatcherTestCases.TestCase;
 import org.apache.ranger.plugin.resourcematcher.TestResourceMatcher.ResourceMatcherTestCases.TestCase.OneTest;
 import org.junit.After;
@@ -112,7 +113,7 @@ public class TestResourceMatcher {
 				}
 
 				boolean expected = oneTest.result;
-				boolean result   = matcher.isMatch(oneTest.input, oneTest.evalContext);
+				boolean result   = matcher.isMatch(oneTest.input, ResourceElementMatchingScope.SELF, oneTest.evalContext);
 
 				assertEquals("isMatch() failed! " + testCase.name + ":" + oneTest.name + ": input=" + oneTest.input, expected, result);
 			}
diff --git a/agents-common/src/test/resources/policyengine/aws_s3_tags.json b/agents-common/src/test/resources/policyengine/aws_s3_tags.json
new file mode 100644
index 000000000..be598893c
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/aws_s3_tags.json
@@ -0,0 +1,33 @@
+{
+    "op":          "add_or_update",
+    "serviceName": "dev_aws-s3",
+    "tagDefinitions": {
+      "1": { "id": 1, "name": "PII" },
+      "2": { "id": 2, "name": "PII-VENDOR" }
+    },
+    "tags": {
+      "1": { "id": 1, "type": "PII" },
+      "2": { "id": 2, "type": "PII-VENDOR" }
+    },
+    "serviceResources": [
+      {
+        "id": 1, "serviceName": "dev_aws-s3",
+        "resourceElements": {
+          "bucketname": { "values": [ "mycompany" ] },
+          "objectpath": { "values": [ "/pii" ], "isRecursive": true }
+        }
+     },
+      {
+        "id": 2, "serviceName": "dev_aws-s3",
+        "resourceElements": {
+          "bucketname": { "values": [ "mycompany" ] },
+          "objectpath": { "values": [ "/vendor/pii" ], "isRecursive": true }
+        }
+     }
+    ],
+    "resourceToTagIds": {
+      "1": [ 1 ],
+      "2": [ 2 ]
+    }
+}
+
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_aws.json b/agents-common/src/test/resources/policyengine/test_policyengine_aws.json
index 118bef534..56e082ad8 100644
--- a/agents-common/src/test/resources/policyengine/test_policyengine_aws.json
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_aws.json
@@ -108,14 +108,14 @@
   "tests":[
     {"name":"ALLOW 'write /tmp/scott' for u=scott for scope SELF_OR_CHILD",
       "request":{
-        "resource":{"elements":{"path":"/tmp/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/scott"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"write","user":"scott","userGroups":[],"requestData":"write /tmp/scott"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId": 200}
     },
     {"name":"DENY 'ANY /tmp/scott' for u=joe for scope SELF_OR_CHILD",
       "request":{
-        "resource":{"elements":{"path":"/tmp/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/scott"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"joe","userGroups":[],"requestData":"ANY /tmp/scott"
       },
       "result":{"isAudited":false,"isAllowed":false,"policyId": -1}
@@ -136,7 +136,7 @@
     },
     {"name":"ALLOW 'write /user/dir' for u=scott for scope SELF_OR_CHILD",
       "request":{
-        "resource":{"elements":{"path":"/user/dir"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/user/dir"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"write","user":"scott","userGroups":[],"requestData":"write /user/dir"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId": 400}
@@ -150,14 +150,14 @@
     },
     {"name":"DENY 'ANY /user/dir' for u=joe for scope SELF_OR_CHILD",
       "request":{
-        "resource":{"elements":{"path":"/user/dir"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/user/dir"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"joe","userGroups":[],"requestData":"ANY /user/dir"
       },
       "result":{"isAudited":true,"isAllowed":false,"policyId": -1}
     },
     {"name":"ALLOW 'read /user/scott' for u=scott for scope SELF_OR_CHILD",
       "request":{
-        "resource":{"elements":{"path":"/user/scott"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/user/scott"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"read","user":"scott","userGroups":[],"requestData":"read /tmp/scott"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId": 500}
@@ -171,7 +171,7 @@
     },
     {"name":"ALLOW 'ANY /' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId":20}
@@ -179,7 +179,7 @@
   ,
     {"name":"ALLOW 'ANY /tmp' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId":40}
@@ -187,7 +187,7 @@
   ,
     {"name":"ALLOW 'ANY /tmp/' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp/"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp/"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId":40}
@@ -195,7 +195,7 @@
   ,
     {"name":"ALLOW 'ANY /tmp/a' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp/a"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/a"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp/a"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId":50}
@@ -203,7 +203,7 @@
   ,
     {"name":"DENY 'ANY /tmp/ac' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp/ac"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/ac"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp/ac"
       },
       "result":{"isAudited":false,"isAllowed":false,"policyId":-1}
@@ -211,7 +211,7 @@
   ,
     {"name":"DENY 'ANY /tmp/ac/d' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp/ac/d"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/ac/d"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp/ac/d"
       },
       "result":{"isAudited":false,"isAllowed":false,"policyId":-1}
@@ -219,7 +219,7 @@
   ,
     {"name":"ALLOW 'ANY /tmp/ac/d/e' for u=user1",
       "request":{
-        "resource":{"elements":{"path":"/tmp/ac/d/e"}}, "resourceMatchingScope": "SELF_OR_CHILD",
+        "resource":{"elements":{"path":"/tmp/ac/d/e"}}, "resourceElementMatchingScopes": { "path": "SELF_OR_CHILD" },
         "accessType":"","user":"user1","userGroups":[],"requestData":"ANY /tmp/ac/d/e"
       },
       "result":{"isAudited":true,"isAllowed":true,"policyId":10}
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_aws_s3.json b/agents-common/src/test/resources/policyengine/test_policyengine_aws_s3.json
new file mode 100644
index 000000000..e2373164c
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_aws_s3.json
@@ -0,0 +1,211 @@
+{
+  "serviceName": "dev_aws-s3",
+
+  "serviceDef": {
+    "name": "aws-s3", "id": 1,
+    "resources": [
+      { "name": "bucketname", "parent":"",           "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": false }, "label": "Bucket Name", "description": "Bucket Name" },
+      { "name": "objectpath", "parent":"bucketname", "level": 2, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",    "matcherOptions": { "wildCard": true, "ignoreCase": false }, "label": "Object Path", "description": "Object Path" }
+    ],
+    "accessTypes": [
+      { "name": "read",   "label": "Read" },
+      { "name": "write",  "label": "Write" },
+      { "name": "delete", "label": "Delete" }
+    ]
+  },
+
+  "policies": [
+    {
+      "id": 10, "name": "s3://mycompany/public", "isEnabled": true, "isAuditEnabled": true,
+      "resources": {
+        "bucketname": { "values": [ "mycompany" ] },
+        "objectpath": { "values": [ "/public" ], "isRecursive": true } },
+      "policyItems": [
+        { "accesses": [ { "type": "read", "isAllowed": true } ], "groups": [ "public" ] }
+      ]
+    },
+    {
+      "id": 20, "name": "s3://mycompany/home/{USER}", "isEnabled": true, "isAuditEnabled": true,
+      "resources": {
+        "bucketname": { "values": [ "mycompany" ] },
+        "objectpath": { "values": [ "/home/{USER}" ], "isRecursive": true } },
+      "policyItems": [
+        { "accesses": [ { "type": "read", "isAllowed": true },  { "type": "write", "isAllowed": true },  { "type": "delete", "isAllowed": true } ], "users": [ "{USER}" ] }
+      ]
+    },
+    {
+      "id": 30, "name": "s3://mycompany/dept/hr", "isEnabled": true, "isAuditEnabled": true,
+      "resources": {
+        "bucketname": { "values": [ "mycompany" ] },
+        "objectpath": { "values": [ "/dept/hr" ], "isRecursive": true } },
+      "policyItems": [
+        { "accesses": [ { "type": "read", "isAllowed": true },  { "type": "write", "isAllowed": true },  { "type": "delete", "isAllowed": true } ], "groups": [ "hr-admins" ] },
+        { "accesses": [ { "type": "read", "isAllowed": true } ], "groups": [ "hr-users" ] }
+      ]
+    }
+  ],
+  "tagPolicyInfo": {
+    "serviceName":"tagdev",
+    "serviceDef": {
+      "name":      "tag", "id": 100,
+      "resources": [
+        { "name": "tag", "type": "string", "level": 1, "parent": "", "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": false }, "label": "TAG", "description": "TAG"
+        }
+      ],
+      "accessTypes": [
+        { "name": "aws-s3:read",   "label": "aws-s3:read" },
+        { "name": "aws-s3:write",  "label": "aws-s3:write" },
+        { "name": "aws-s3:delete", "label": "aws-s3:delete" }
+      ],
+      "contextEnrichers": [
+        {
+          "name" :     "TagEnricher",
+          "enricher" : "org.apache.ranger.plugin.contextenricher.RangerTagEnricher",
+          "enricherOptions" : {
+             "tagRetrieverClassName":       "org.apache.ranger.plugin.contextenricher.RangerFileBasedTagRetriever",
+             "tagRefresherPollingInterval": 60000,
+             "serviceTagsFileName":         "/policyengine/aws_s3_tags.json"}
+        }
+      ]
+    },
+    "tagPolicies": [
+      {
+        "id": 1001, "name": "PII", "isEnabled": true, "isAuditEnabled": true,
+        "resources": { "tag": { "values": [ "PII" ] } },
+        "policyItems": [
+          { "accesses": [ { "type": "aws-s3:read", "isAllowed": true } ], "users": [ "user3" ] }
+        ]
+      },
+      {
+        "id": 1002, "name": "PII-VENDOR", "isEnabled": true, "isAuditEnabled": true,
+        "resources": { "tag": { "values": [ "PII-VENDOR" ] } },
+        "policyItems": [
+          { "accesses": [ { "type": "aws-s3:read", "isAllowed": true } ], "users": [ "user4" ] }
+        ]
+      }
+    ]
+  },
+  "tests": [
+    {
+      "name":    "Verify user1 has read access to some object under s3://mycompany",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user1"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 10 }
+    },
+    {
+      "name":    "Verify user1 has read access to some object under s3://mycompany/public",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/public/" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user1"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 10 }
+    },
+    {
+      "name":    "Verify user1 has no write access to any object under s3://mycompany/public",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/public/" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user1"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    },
+    {
+      "name":    "Verify user1 has write access to some object under s3://mycompany/home",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/home" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user1"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 20 }
+    },
+    {
+      "name":    "Verify user1 has no write access to any object under s3://mycompany/dept",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/dept" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user1"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    },
+    {
+      "name":    "Verify user3 has read access to some objects under s3://mycompany/",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user3"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 1001 }
+    },
+    {
+      "name":    "Verify user3 has write access to some objects under s3://mycompany/",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user3"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 20 }
+    },
+    {
+      "name":    "Verify user3 has read access to some objects under s3://mycompany/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user3"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 1001 }
+    },
+    {
+      "name":    "Verify user3 has no write access to any object under s3://mycompany/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user3"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    },
+    {
+      "name":    "Verify user3 has no read access to any object under s3://mycompany/vendor/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/vendor/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user3"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    },
+    {
+      "name":    "Verify user4 has read access to some objects under s3://mycompany/vendor",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/vendor" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user4"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 1002 }
+    },
+    {
+      "name":    "Verify user4 has read access to some objects under s3://mycompany/vendor/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/vendor/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user4"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 1002 }
+    },
+    {
+      "name":    "Verify user4 has read access to some objects under s3://mycompany/vendor/pii/test",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/vendor/pii/test" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user4"
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 1002 }
+    },
+    {
+      "name":    "Verify user4 has no read access to any object under s3://mycompany/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "read", "user": "user4"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    },
+    {
+      "name":    "Verify user4 has no write access to any object under s3://mycompany/pii",
+      "request": {
+        "resource":   { "elements": { "bucketname": "mycompany", "objectpath": "/pii" } }, "resourceElementMatchingScopes": { "objectpath": "SELF_OR_PREFIX" },
+        "accessType": "write", "user": "user4"
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    }
+  ]
+}
+
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_kafka.json b/agents-common/src/test/resources/policyengine/test_policyengine_kafka.json
new file mode 100644
index 000000000..89ab9c0b5
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_kafka.json
@@ -0,0 +1,157 @@
+{
+  "serviceName": "kafkadev",
+
+  "serviceDef": {
+    "name": "kafka", "id": 9,
+    "resources": [
+      { "name": "topic",           "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Topic",            "description": "Topic",            "accessTypeRestrictions": [ "create", "delete", "configure", "alter", "alter_configs", "describe", "describe_configs", "consume", "publish" ] },
+      { "name": "transactionalid", "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Transactional Id", "description": "Transactional Id", "accessTypeRestrictions": [ "describe", "publish" ] },
+      { "name": "cluster",         "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Cluster",          "description": "Cluster",          "accessTypeRestrictions": [ "create", "configure", "alter", "alter_configs", "describe", "describe_configs", "kafka_admin", "idempotent_write", "cluster_action" ] },
+      { "name": "delegationtoken", "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Delegation Token", "description": "Delegation Token", "accessTypeRestrictions": [ "describe" ] },
+      { "name": "consumergroup",   "level": 1, "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Consumer Group",   "description": "Consumer Group",   "accessTypeRestrictions": [ "consume", "describe", "delete" ] }
+    ],
+    "accessTypes": [
+      { "name": "publish",     "label": "Publish",     "impliedGrants": [ "describe" ] },
+      { "name": "consume",     "label": "Consume",     "impliedGrants": [ "describe" ] },
+      { "name": "configure",   "label": "Configure",   "impliedGrants": [ "describe" ] },
+      { "name": "describe",    "label": "Describe" },
+      { "name": "kafka_admin", "label": "Kafka Admin", "impliedGrants": [ "publish", "consume", "configure", "describe", "create", "delete", "describe_configs", "alter_configs", "alter", "idempotent_write", "cluster_action" ] },
+      { "name": "create",           "label": "Create" },
+      { "name": "delete",           "label": "Delete", "impliedGrants": [ "describe" ] },
+      { "name": "idempotent_write", "label": "Idempotent Write" },
+      { "name": "describe_configs", "label": "Describe Configs" },
+      { "name": "alter_configs",    "label": "Alter Configs" },
+      { "name": "cluster_action",   "label": "Cluster Action" },
+      { "name": "alter",            "label": "alter" }
+    ]
+  },
+
+  "policies": [
+    {
+      "id": 10,"name": "10: test-topic publish/consume allowed","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "topic": {"values": [ "test-topic-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "publish", "isAllowed": true },{"type": "consume", "isAllowed": true }], "users": [ "user1" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 101,"name": "101: test-topic publish/consume allowed","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "topic": {"values": [ "test-topic-2" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "publish", "isAllowed": true },{"type": "consume", "isAllowed": true }], "users": [ "user2" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 102,"name": "102: test-topic publish/consume allowed","isEnabled": true,"isAuditEnabled": true,
+      "resources": {"topic": {"values": [ "test-topic-1","test-topic-4" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "consume", "isAllowed": true }], "users": [ "user3" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 103,"name": "103: test-topic publish/consume allowed","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "topic": {"values": [ "test-topic-1","test-topic-5" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "consume", "isAllowed": true }], "users": [ "user4", "user5" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 104,"name": "104: test-topic publish/consume allowed","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "topic": {"values": [ "test-topic-7" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "publish", "isAllowed": true },{"type": "consume", "isAllowed": true }], "users": [ "user6" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 20,"name": "02: transation id","isEnabled": true,"isAuditEnabled": true,"policyType": 1,
+      "resources": { "delegationtoken": {"values": [ "tid-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "publish", "isAllowed": true }], "users": [ "user1" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 30,"name": "create/alter access for user1 on cluster-1","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "cluster": {"values": [ "cluseter-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "create", "isAllowed": true },{"type": "alter", "isAllowed": true }], "users": [ "user1" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 301,"name": "Alter access for user31 on cluster-2","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "cluster": {"values": [ "cluster-2" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "alter", "isAllowed": true }], "users": [ "user31" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 302,"name": "Alter access for user32 on cluster-1","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "cluster": {"values": [ "cluseter-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "alter", "isAllowed": true }], "users": [ "user32" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 40,"name": "delegationtoken","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "delegationtoken": {"values": [ "dt-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "describe", "isAllowed": true }], "users": [ "user1" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 50,"name": "consumergroup-1 access","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "consumergroup": {"values": [ "consumergroup-1" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "consume", "isAllowed": true }], "users": [ "user1" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 52,"name": "consumergroup-2 access for user4","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "consumergroup": {"values": [ "consumergroup-2" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "consume", "isAllowed": true }], "users": [ "user4" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 110,"name": "110: test-topic-1/2 consume allowed for user2","isEnabled": true,"isAuditEnabled": true,
+      "resources": { "topic": {"values": [ "test-topic-1", "test-topic-2" ], "isRecursive": true } },
+      "policyItems": [
+        {"accesses": [{"type": "consume", "isAllowed": true }], "users": [ "user2" ], "groups": [] }
+      ]
+    },
+    {
+      "id": 111, "name": "110: new-topic-1/2 allowed for user2", "isEnabled": true, "isAuditEnabled": true,
+      "resources": { "topic": { "values": [ "new-topic-1", "new-topic-2" ], "isRecursive": true } },
+      "policyItems": [
+        { "accesses": [ { "type": "consume", "isAllowed": true } ], "users": [ "user2" ], "groups": [] }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "name":    "Any topic Consume access for user3",
+      "request": {
+        "resource":   { "elements": { "topic": "" } }, "resourceElementMatchingScopes": { "topic": "SELF_OR_PREFIX" },
+        "accessType": "consume", "user": "user3", "userGroups": []
+      },
+      "result": { "isAudited": true, "isAllowed": true, "policyId": 102 }
+    },
+    {
+      "name":    "Any consumergroup consume access for user1",
+      "request": {
+        "resource":   { "elements": { "consumergroup": "" } }, "resourceElementMatchingScopes": { "consumergroup": "SELF_OR_PREFIX" },
+        "accessType": "consume", "user": "user1", "userGroups": []
+      },
+      "result": { "isAudited": true, "isAllowed": true," policyId": 50 }
+    },
+
+    {
+      "name":    "Any consumergroup consume access for user3",
+      "request": {
+        "resource":   { "elements": { "consumergroup": "" } }, "resourceElementMatchingScopes": { "consumergroup": "SELF_OR_PREFIX" },
+        "accessType": "consume", "user": "user3", "userGroups": []
+      },
+      "result": { "isAudited": true, "isAllowed": false, "policyId": -1 }
+    }
+  ]
+}
+