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 8d17b4b9d RANGER-4967: Refactor RangerTagEnricher class for reusability
8d17b4b9d is described below
commit 8d17b4b9da26bc55287e0d245edd194c5471744b
Author: Abhay Kulkarni <[email protected]>
AuthorDate: Wed Oct 23 10:07:09 2024 -0700
RANGER-4967: Refactor RangerTagEnricher class for reusability
---
.../plugin/contextenricher/RangerTagEnricher.java | 220 ++++++---------------
.../plugin/util/CachedResourceEvaluators.java | 172 ++++++++++++++++
2 files changed, 229 insertions(+), 163 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 63ed47ded..c9ca7d822 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
@@ -21,19 +21,16 @@ package org.apache.ranger.plugin.contextenricher;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
-import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.authorization.utils.JsonUtils;
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.RangerServiceDef.RangerResourceDef;
import org.apache.ranger.plugin.model.RangerServiceResource;
import org.apache.ranger.plugin.model.RangerTag;
import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
-import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceElementMatchingScope;
import
org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceMatchingScope;
import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
@@ -42,18 +39,16 @@ import
org.apache.ranger.plugin.policyengine.RangerPluginContext;
import org.apache.ranger.plugin.policyengine.RangerResourceTrie;
import
org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher;
import
org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
-import org.apache.ranger.plugin.policyresourcematcher.RangerResourceEvaluator;
import org.apache.ranger.plugin.util.DownloadTrigger;
import org.apache.ranger.plugin.util.DownloaderTask;
import org.apache.ranger.plugin.service.RangerAuthContext;
+import org.apache.ranger.plugin.util.CachedResourceEvaluators;
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.ServiceDefUtil;
import org.apache.ranger.plugin.util.ServiceTags;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,12 +76,11 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
private static final Logger LOG =
LoggerFactory.getLogger(RangerTagEnricher.class);
private static final Logger PERF_CONTEXTENRICHER_INIT_LOG =
RangerPerfTracer.getPerfLogger("contextenricher.init");
- private static final Logger PERF_TRIE_OP_LOG =
RangerPerfTracer.getPerfLogger("resourcetrie.retrieval");
private static final Logger PERF_SET_SERVICETAGS_LOG =
RangerPerfTracer.getPerfLogger("tagenricher.setservicetags");
private static final Logger PERF_SERVICETAGS_RETRIEVAL_LOG =
RangerPerfTracer.getPerfLogger("tagenricher.tags.retrieval");
private static final String TAG_REFRESHER_POLLINGINTERVAL_OPTION =
"tagRefresherPollingInterval";
- public static final String TAG_RETRIEVER_CLASSNAME_OPTION =
"tagRetrieverClassName";
+ public static final String TAG_RETRIEVER_CLASSNAME_OPTION =
"tagRetrieverClassName";
private static final String TAG_DISABLE_TRIE_PREFILTER_OPTION =
"disableTrieLookupPrefilter";
private RangerTagRefresher tagRefresher;
@@ -296,6 +290,9 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
LOG.debug("==>
RangerTagEnricher.setServiceTags(serviceTags=" + serviceTags + ",
rebuildOnlyIndex=" + rebuildOnlyIndex + ")");
}
+ final EnrichedServiceTags localEnrichedServiceTags;
+ final Set<String> keysToRemoveFromCache = new
HashSet<>();
+
try (RangerReadWriteLock.RangerLock writeLock =
this.lock.getWriteLock()) {
if (LOG.isDebugEnabled()) {
@@ -305,13 +302,13 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
}
RangerPerfTracer perf = null;
-
if(RangerPerfTracer.isPerfTraceEnabled(PERF_SET_SERVICETAGS_LOG)) {
+ if
(RangerPerfTracer.isPerfTraceEnabled(PERF_SET_SERVICETAGS_LOG)) {
perf =
RangerPerfTracer.getPerfTracer(PERF_SET_SERVICETAGS_LOG,
"RangerTagEnricher.setServiceTags(newTagVersion=" + serviceTags.getTagVersion()
+ ",isDelta=" + serviceTags.getIsDelta() + ")");
}
if (serviceTags == null) {
LOG.info("ServiceTags is null for service " +
serviceName);
- enrichedServiceTags = null;
+ localEnrichedServiceTags = null;
} else {
if (dedupStrings) {
serviceTags.dedupStrings();
@@ -323,7 +320,7 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
LOG.info("Number of duplicate
tags removed from the received serviceTags:[" + countOfDuplicateTags + "].
Number of tags in the de-duplicated serviceTags :[" +
serviceTags.getTags().size() + "].");
}
- processServiceTags(serviceTags);
+ localEnrichedServiceTags =
processServiceTags(serviceTags);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Received service-tag
deltas:" + serviceTags);
@@ -335,6 +332,7 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
if (LOG.isDebugEnabled()) {
LOG.debug("No change to
service-tags other than version change");
}
+ localEnrichedServiceTags =
enrichedServiceTags;
} else {
if
(serviceTags.getTagsChangeExtent() != ServiceTags.TagsChangeExtent.TAGS) {
Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> trieMap;
@@ -345,22 +343,32 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
trieMap =
writeLock.isLockingEnabled() ? enrichedServiceTags.getServiceResourceTrie() :
copyServiceResourceTrie();
}
-
processServiceTagDeltas(serviceTags, allServiceTags, trieMap);
+
localEnrichedServiceTags = processServiceTagDeltas(serviceTags, allServiceTags,
trieMap, keysToRemoveFromCache);
} else {
if
(LOG.isDebugEnabled()) {
LOG.debug("Delta contains only tag attribute changes");
}
-
List<RangerServiceResourceMatcher> resourceMatchers = enrichedServiceTags !=
null ? enrichedServiceTags.getServiceResourceMatchers() : new ArrayList<>();
+
List<RangerServiceResourceMatcher> resourceMatchers
= enrichedServiceTags != null ?
enrichedServiceTags.getServiceResourceMatchers() : new ArrayList<>();
Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie =
enrichedServiceTags != null ? enrichedServiceTags.getServiceResourceTrie() :
new HashMap<>();
- enrichedServiceTags =
new EnrichedServiceTags(allServiceTags, resourceMatchers, serviceResourceTrie);
+
localEnrichedServiceTags = new EnrichedServiceTags(allServiceTags,
resourceMatchers, serviceResourceTrie);
}
}
}
-
}
- setEnrichedServiceTagsInPlugin();
- cache.clearCache();
+ synchronized (RangerTagEnricher.class) {
+ enrichedServiceTags = localEnrichedServiceTags;
+
+ if (serviceTags != null) {
+ if (serviceTags.getIsDelta()) {
+
cache.removeCacheEvaluators(keysToRemoveFromCache);
+ keysToRemoveFromCache.clear();
+ } else {
+ cache.clearCache();
+ }
+ }
+ setEnrichedServiceTagsInPlugin();
+ }
RangerPerfTracer.logAlways(perf);
}
@@ -433,14 +441,16 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
return new RangerReadWriteLock(useReadWriteLock);
}
- private void processServiceTags(ServiceTags serviceTags) {
+ private EnrichedServiceTags processServiceTags(ServiceTags serviceTags)
{
if (LOG.isDebugEnabled()) {
LOG.debug("Processing all service-tags");
}
+ final EnrichedServiceTags ret;
+
if (CollectionUtils.isEmpty(serviceTags.getServiceResources()))
{
LOG.info("There are no tagged resources for service " +
serviceName);
- enrichedServiceTags = null;
+ ret = null;
} else {
ResourceHierarchies hierarchies =
new ResourceHierarchies();
List<RangerServiceResourceMatcher> resourceMatchers =
new ArrayList<>();
@@ -470,15 +480,18 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
serviceResourceTrie.put(resourceDef.getName(), new
RangerResourceTrie(resourceDef, resourceMatchers,
getPolicyEngineOptions().optimizeTagTrieForRetrieval,
getPolicyEngineOptions().optimizeTagTrieForSpace, null));
}
}
- enrichedServiceTags = new
EnrichedServiceTags(serviceTags, resourceMatchers, serviceResourceTrie);
+ ret = new EnrichedServiceTags(serviceTags,
resourceMatchers, serviceResourceTrie);
}
+ return ret;
}
- private void processServiceTagDeltas(ServiceTags deltas, ServiceTags
allServiceTags, Map<String, RangerResourceTrie<RangerServiceResourceMatcher>>
serviceResourceTrie) {
+ private EnrichedServiceTags processServiceTagDeltas(ServiceTags deltas,
ServiceTags allServiceTags, Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie,
Set<String> keysToRemoveFromCache) {
if (LOG.isDebugEnabled()) {
LOG.debug("Delta contains changes other than tag
attribute changes, [" + deltas.getTagsChangeExtent() + "]");
}
+ final EnrichedServiceTags ret;
+
boolean isInError = false;
ResourceHierarchies hierarchies = new
ResourceHierarchies();
@@ -491,9 +504,9 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
List<RangerServiceResource> changedServiceResources =
deltas.getServiceResources();
for (RangerServiceResource serviceResource :
changedServiceResources) {
- final boolean removedOldServiceResource =
MapUtils.isEmpty(serviceResource.getResourceElements()) ||
removeOldServiceResource(serviceResource, resourceMatchers,
serviceResourceTrie);
+ final RangerAccessResource removedAccessResource =
MapUtils.isEmpty(serviceResource.getResourceElements()) ? null :
removeOldServiceResource(serviceResource, resourceMatchers,
serviceResourceTrie);
- if (removedOldServiceResource) {
+ if (removedAccessResource != null) {
if
(!StringUtils.isEmpty(serviceResource.getResourceSignature())) {
RangerServiceResourceMatcher
resourceMatcher = createRangerServiceResourceMatcher(serviceResource,
serviceDefHelper, hierarchies, getPluginContext());
@@ -529,6 +542,7 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
LOG.debug("Service-resource:[id=" + serviceResource.getId() + "] is deleted as
its resource-signature is empty. No need to create it!");
}
}
+
keysToRemoveFromCache.add(removedAccessResource.getCacheKey());
} else {
isInError = true;
}
@@ -540,16 +554,20 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
if (isInError) {
LOG.error("Error in processing tag-deltas. Will
continue to use old tags");
deltas.setTagVersion(-1L);
+ keysToRemoveFromCache.clear();
+ ret = enrichedServiceTags;
} else {
for (Map.Entry<String,
RangerResourceTrie<RangerServiceResourceMatcher>> entry :
serviceResourceTrie.entrySet()) {
entry.getValue().wrapUpUpdate();
}
- enrichedServiceTags = new
EnrichedServiceTags(allServiceTags, resourceMatchers, serviceResourceTrie);
+ ret = new EnrichedServiceTags(allServiceTags,
resourceMatchers, serviceResourceTrie);
}
+ return ret;
}
- private boolean removeOldServiceResource(RangerServiceResource
serviceResource, List<RangerServiceResourceMatcher> resourceMatchers,
Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> resourceTries) {
- boolean ret = true;
+ private RangerAccessResource
removeOldServiceResource(RangerServiceResource serviceResource,
List<RangerServiceResourceMatcher> resourceMatchers, Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> resourceTries) {
+ final RangerAccessResource ret;
+ boolean result = true;
if (enrichedServiceTags != null) {
if (LOG.isDebugEnabled()) {
@@ -562,6 +580,8 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
accessResource.setValue(entry.getKey(),
entry.getValue().getValues());
}
+ accessResource.setServiceDef(serviceDef);
+
if (LOG.isDebugEnabled()) {
LOG.debug("RangerAccessResource:[" +
accessResource + "] created to represent service-resource[" + serviceResource +
"] to find evaluators from trie-map");
}
@@ -569,7 +589,7 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
RangerAccessRequestImpl request = new
RangerAccessRequestImpl();
request.setResource(accessResource);
- Collection<RangerServiceResourceMatcher> oldMatchers =
getEvaluators(request, enrichedServiceTags);
+ Collection<RangerServiceResourceMatcher> oldMatchers =
CachedResourceEvaluators.getEvaluators(request,
enrichedServiceTags.getServiceResourceTrie(), cache);
if (LOG.isDebugEnabled()) {
LOG.debug("Found [" + oldMatchers + "] matchers
for service-resource[" + serviceResource + "]");
@@ -607,20 +627,27 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
} else {
LOG.error("Cannot find
resourceDef with name:[" + resourceDefName + "]. Should NOT happen!!");
LOG.error("Setting tagVersion
to -1 to ensure that in the next download all tags are downloaded");
- ret = false;
+ result = false;
break;
}
}
}
- if (ret) {
+ if (result) {
resourceMatchers.removeAll(oldMatchers);
if (LOG.isDebugEnabled()) {
LOG.debug("Found and removed [" +
oldMatchers + "] matchers for service-resource[" + serviceResource + "] from
trie-map");
}
+
+ ret = accessResource;
+ } else {
+ ret = null;
}
+ } else {
+ ret = null;
}
+
return ret;
}
@@ -716,7 +743,7 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
ret =
enrichedServiceTags.getTagsForEmptyResourceAndAnyAccess();
} else {
- final Collection<RangerServiceResourceMatcher>
serviceResourceMatchers = getEvaluators(request, enrichedServiceTags);
+ final Collection<RangerServiceResourceMatcher>
serviceResourceMatchers = CachedResourceEvaluators.getEvaluators(request,
enrichedServiceTags.getServiceResourceTrie(), cache);
if
(CollectionUtils.isNotEmpty(serviceResourceMatchers)) {
for (RangerServiceResourceMatcher
resourceMatcher : serviceResourceMatchers) {
@@ -767,121 +794,6 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
return ret;
}
- private static class CachedResourceEvaluators {
- private final Map<String, Map<Map<String,
ResourceElementMatchingScope>, Collection<RangerServiceResourceMatcher>>> cache
= new HashMap<>();
- private final RangerReadWriteLock
cacheLock = new
RangerReadWriteLock(true);
-
- CachedResourceEvaluators() {}
-
- Collection<RangerServiceResourceMatcher> getEvaluators(String
resourceKey, Map<String, ResourceElementMatchingScope> scopes) {
- Collection<RangerServiceResourceMatcher> ret;
-
- try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getReadLock()) {
- ret = cache.getOrDefault(resourceKey,
Collections.emptyMap()).get(scopes);
- }
-
- return ret;
- }
-
- void cacheEvaluators(String resource, Map<String,
ResourceElementMatchingScope> scopes, Collection<RangerServiceResourceMatcher>
evaluators) {
- try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getWriteLock()) {
- cache.computeIfAbsent(resource, k -> new
HashMap<>()).put(scopes, evaluators);
- }
- }
-
- void clearCache() {
- try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getWriteLock()) {
- cache.clear();
- }
- }
- }
-
- private Collection<RangerServiceResourceMatcher>
getEvaluators(RangerAccessRequest request, EnrichedServiceTags
enrichedServiceTags) {
- if(LOG.isDebugEnabled()) {
- LOG.debug("==>
RangerTagEnricher.getEvaluators(request=" + request + ")");
- }
-
- Collection<RangerServiceResourceMatcher>
ret = null;
- final RangerAccessResource
resource = request.getResource();
- final Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie =
enrichedServiceTags.getServiceResourceTrie();
-
- if (resource == null || resource.getKeys() == null ||
resource.getKeys().isEmpty() || serviceResourceTrie == null) {
- ret = enrichedServiceTags.getServiceResourceMatchers();
- } else {
- RangerPerfTracer perf = null;
-
- if
(RangerPerfTracer.isPerfTraceEnabled(PERF_TRIE_OP_LOG)) {
- perf =
RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG,
"RangerTagEnricher.getEvaluators(resource=" + resource.getAsString() + ")");
- }
-
- final Predicate predicate =
excludeDescendantMatches(request) ? new
SelfOrAncestorPredicate(serviceDefHelper.getResourceDef(resource.getLeafName()))
: null;
-
- if (predicate != null) {
- ret =
cache.getEvaluators(resource.getCacheKey(),
request.getResourceElementMatchingScopes());
- }
-
- if (ret == null) {
- ret =
RangerResourceEvaluatorsRetriever.getEvaluators(serviceResourceTrie,
resource.getAsMap(), request.getResourceElementMatchingScopes(), predicate);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Found [" + ret.size() + "]
service-resource-matchers for service-resource [" + resource.getAsString() +
"]");
- }
-
- if (predicate != null) {
-
cache.cacheEvaluators(resource.getCacheKey(),
request.getResourceElementMatchingScopes(), ret);
- }
- } else {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Found [" + ret.size() + "]
service-resource-matchers for service-resource [" + resource.getAsString() + "]
in the cache");
- }
- }
-
- RangerPerfTracer.logAlways(perf);
- }
- if (ret == null) {
- ret = new ArrayList<>();
- }
-
- if(LOG.isDebugEnabled()) {
- LOG.debug("<==
RangerTagEnricher.getEvaluators(request=" + request + "): evaluators=" + ret);
- }
-
- return ret;
- }
-
- private boolean excludeDescendantMatches(RangerAccessRequest request) {
- final boolean ret;
-
- if (request.isAccessTypeAny() ||
RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext()) ||
request.getResourceMatchingScope().equals(ResourceMatchingScope.SELF_OR_DESCENDANTS))
{
- ret = false;
- } else {
- RangerAccessResource resource = request.getResource();
- String leafName = resource.getLeafName();
-
- if (StringUtils.isNotEmpty(leafName)) {
- RangerServiceDefHelper helper = new
RangerServiceDefHelper(getServiceDef());
- Set<List<RangerResourceDef>> hierarchies =
helper.getResourceHierarchies(RangerPolicy.POLICY_TYPE_ACCESS,
resource.getKeys());
-
- // skip caching if the leaf of accessed
resource is the deepest in the only applicable hierarchy
- if (hierarchies.size() == 1) {
- List<RangerResourceDef> theHierarchy
= hierarchies.iterator().next();
- RangerResourceDef leafOfHierarchy
= theHierarchy.get(theHierarchy.size() - 1);
-
- if
(StringUtils.equals(leafOfHierarchy.getName(), leafName)) {
- ret = false;
- } else {
- ret = true;
- }
- } else {
- ret = true;
- }
- } else {
- ret = false;
- }
- }
- return ret;
- }
-
private static Set<RangerTagForEval> getTagsForServiceResource(Date
accessTime, final ServiceTags serviceTags, final RangerServiceResource
serviceResource, final RangerPolicyResourceMatcher.MatchType matchType) {
Set<RangerTagForEval> ret = new HashSet<>();
@@ -1238,22 +1150,4 @@ public class RangerTagEnricher extends
RangerAbstractContextEnricher {
}
}
- private static class SelfOrAncestorPredicate implements Predicate {
- private final RangerServiceDef.RangerResourceDef
leafResourceDef;
-
- public
SelfOrAncestorPredicate(RangerServiceDef.RangerResourceDef leafResourceDef) {
- this.leafResourceDef = leafResourceDef;
- }
-
- @Override
- public boolean evaluate(Object o) {
- if (o instanceof RangerResourceEvaluator) {
- RangerResourceEvaluator evaluator =
(RangerResourceEvaluator) o;
-
- return
evaluator.isLeaf(leafResourceDef.getName()) ||
evaluator.isAncestorOf(leafResourceDef);
- }
-
- return false;
- }
- }
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/util/CachedResourceEvaluators.java
b/agents-common/src/main/java/org/apache/ranger/plugin/util/CachedResourceEvaluators.java
new file mode 100644
index 000000000..ff2d04376
--- /dev/null
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/util/CachedResourceEvaluators.java
@@ -0,0 +1,172 @@
+/*
+ * 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.Predicate;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ranger.plugin.contextenricher.RangerServiceResourceMatcher;
+import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class CachedResourceEvaluators {
+ private final Map<String, Map<Map<String,
RangerAccessRequest.ResourceElementMatchingScope>,
Collection<RangerServiceResourceMatcher>>> cache = new HashMap<>();
+ private final RangerReadWriteLock
cacheLock = new
RangerReadWriteLock(true);
+
+ private static final Logger LOG =
LoggerFactory.getLogger(CachedResourceEvaluators.class);
+ private static final Logger PERF_EVALUATORS_RETRIEVAL_LOG =
RangerPerfTracer.getPerfLogger("CachedResourceEvaluators.retrieval");
+
+ public CachedResourceEvaluators() {}
+
+ public Collection<RangerServiceResourceMatcher> getEvaluators(String
resourceKey, Map<String, RangerAccessRequest.ResourceElementMatchingScope>
scopes) {
+ Collection<RangerServiceResourceMatcher> ret;
+
+ try (RangerReadWriteLock.RangerLock ignored = cacheLock.getReadLock())
{
+ ret = cache.getOrDefault(resourceKey,
Collections.emptyMap()).get(scopes);
+ }
+
+ return ret;
+ }
+
+ public void cacheEvaluators(String resource, Map<String,
RangerAccessRequest.ResourceElementMatchingScope> scopes,
Collection<RangerServiceResourceMatcher> evaluators) {
+ try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getWriteLock()) {
+ cache.computeIfAbsent(resource, k -> new HashMap<>()).put(scopes,
evaluators);
+ }
+ }
+
+ public void removeCacheEvaluators(Set<String> resources) {
+ try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getWriteLock()) {
+ resources.forEach(cache::remove);
+ }
+ }
+
+ public void clearCache() {
+ try (RangerReadWriteLock.RangerLock ignored =
cacheLock.getWriteLock()) {
+ cache.clear();
+ }
+ }
+
+ public static Collection<RangerServiceResourceMatcher>
getEvaluators(RangerAccessRequest request, Map<String,
RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie,
CachedResourceEvaluators cache) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> CachedResourceEvaluators.getEvaluators(request=" +
request + ")");
+ }
+
+ Collection<RangerServiceResourceMatcher> ret = null;
+ final RangerAccessResource resource =
request.getResource();
+ RangerServiceDefHelper helper = new
RangerServiceDefHelper(resource.getServiceDef());
+
+ RangerPerfTracer perf = null;
+
+ if
(RangerPerfTracer.isPerfTraceEnabled(PERF_EVALUATORS_RETRIEVAL_LOG)) {
+ perf =
RangerPerfTracer.getPerfTracer(PERF_EVALUATORS_RETRIEVAL_LOG,
"CachedResourceEvaluators.getEvaluators(resource=" + resource.getAsString() +
")");
+ }
+
+ final Predicate predicate = !(request.isAccessTypeAny() ||
RangerAccessRequestUtil.getIsAnyAccessInContext(request.getContext()) ||
RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS.equals(request.getResourceMatchingScope()))
&& excludeDescendantMatches(resource) ? new
SelfOrAncestorPredicate(helper.getResourceDef(resource.getLeafName())) : null;
+
+ if (predicate != null) {
+ ret = cache.getEvaluators(resource.getCacheKey(),
request.getResourceElementMatchingScopes());
+ }
+
+ if (ret == null) {
+ ret =
RangerResourceEvaluatorsRetriever.getEvaluators(serviceResourceTrie,
resource.getAsMap(), request.getResourceElementMatchingScopes(), predicate);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found [" + ret.size() + "]
service-resource-matchers for service-resource [" + resource.getAsString() +
"]");
+ }
+
+ if (predicate != null) {
+ cache.cacheEvaluators(resource.getCacheKey(),
request.getResourceElementMatchingScopes(), ret);
+ }
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found [" + ret.size() + "]
service-resource-matchers for service-resource [" + resource.getAsString() + "]
in the cache");
+ }
+ }
+
+ RangerPerfTracer.logAlways(perf);
+
+ if (ret == null) {
+ ret = new ArrayList<>();
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== CachedResourceEvaluators.getEvaluators(request=" +
request + "): evaluators=" + ret);
+ }
+
+ return ret;
+ }
+
+ public static boolean excludeDescendantMatches(RangerAccessResource
resource) {
+ final boolean ret;
+
+ String leafName = resource.getLeafName();
+
+ if (StringUtils.isNotEmpty(leafName)) {
+ RangerServiceDefHelper helper = new
RangerServiceDefHelper(resource.getServiceDef());
+ Set<List<RangerServiceDef.RangerResourceDef>> hierarchies =
helper.getResourceHierarchies(RangerPolicy.POLICY_TYPE_ACCESS,
resource.getKeys());
+
+ // skip caching if the leaf of accessed resource is the deepest in
the only applicable hierarchy
+ if (hierarchies.size() == 1) {
+ List<RangerServiceDef.RangerResourceDef> theHierarchy =
hierarchies.iterator().next();
+ RangerServiceDef.RangerResourceDef leafOfHierarchy =
theHierarchy.get(theHierarchy.size() - 1);
+
+ ret = !StringUtils.equals(leafOfHierarchy.getName(), leafName);
+ } else {
+ ret = true;
+ }
+ } else {
+ ret = false;
+ }
+ return ret;
+ }
+
+ private static class SelfOrAncestorPredicate implements Predicate {
+ private final RangerServiceDef.RangerResourceDef leafResourceDef;
+
+ public SelfOrAncestorPredicate(RangerServiceDef.RangerResourceDef
leafResourceDef) {
+ this.leafResourceDef = leafResourceDef;
+ }
+
+ @Override
+ public boolean evaluate(Object o) {
+ if (o instanceof RangerResourceEvaluator) {
+ RangerResourceEvaluator evaluator = (RangerResourceEvaluator)
o;
+
+ return evaluator.isLeaf(leafResourceDef.getName()) ||
evaluator.isAncestorOf(leafResourceDef);
+ }
+
+ return false;
+ }
+ }
+}