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