RANGER-2061: Add policy engine support to get summary user and group ACLs for a resource
Project: http://git-wip-us.apache.org/repos/asf/ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/ranger/commit/3b510f8c Tree: http://git-wip-us.apache.org/repos/asf/ranger/tree/3b510f8c Diff: http://git-wip-us.apache.org/repos/asf/ranger/diff/3b510f8c Branch: refs/heads/master Commit: 3b510f8c07271e2e51b5a9151a0d26f7084e3792 Parents: c8f67ce Author: Abhay Kulkarni <akulka...@hortonworks.com> Authored: Mon Apr 9 14:29:36 2018 -0700 Committer: Abhay Kulkarni <akulka...@hortonworks.com> Committed: Mon Apr 9 14:29:36 2018 -0700 ---------------------------------------------------------------------- .../RangerScriptConditionEvaluator.java | 2 +- .../RangerAbstractContextEnricher.java | 6 + .../contextenricher/RangerContextEnricher.java | 2 + .../contextenricher/RangerTagEnricher.java | 45 +- .../policyengine/RangerAccessRequestImpl.java | 2 +- .../plugin/policyengine/RangerPolicyEngine.java | 4 + .../policyengine/RangerPolicyEngineImpl.java | 158 ++++- .../policyengine/RangerPolicyEngineOptions.java | 3 + .../plugin/policyengine/RangerResourceACLs.java | 233 ++++++++ .../RangerAbstractPolicyEvaluator.java | 3 + .../RangerAbstractPolicyItemEvaluator.java | 2 +- .../RangerDefaultPolicyEvaluator.java | 319 +++++++++- .../policyevaluator/RangerPolicyEvaluator.java | 310 +++++++++- .../RangerPolicyItemEvaluator.java | 1 - .../plugin/service/RangerAuthContext.java | 230 ++++++++ .../service/RangerAuthContextListener.java | 25 + .../ranger/plugin/service/RangerBasePlugin.java | 40 +- .../plugin/policyengine/TestPolicyACLs.java | 211 +++++++ .../plugin/policyengine/TestPolicyEngine.java | 15 +- agents-common/src/test/resources/log4j.xml | 16 +- .../resources/policyengine/ACLResourceTags.json | 207 +++++++ .../policyengine/test_aclprovider_default.json | 586 +++++++++++++++++++ .../test_policyengine_tag_hive.json | 2 +- 23 files changed, 2377 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java index 5febf95..5b66539 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java @@ -117,7 +117,7 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu } } catch (NullPointerException nullp) { - LOG.error("RangerScriptConditionEvaluator.isMatched(): eval called with NULL argument(s)"); + LOG.error("RangerScriptConditionEvaluator.isMatched(): eval called with NULL argument(s)", nullp); } catch (ScriptException exception) { LOG.error("RangerScriptConditionEvaluator.isMatched(): failed to evaluate script," + http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAbstractContextEnricher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAbstractContextEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAbstractContextEnricher.java index f6e462c..a745112 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAbstractContextEnricher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAbstractContextEnricher.java @@ -29,6 +29,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; public abstract class RangerAbstractContextEnricher implements RangerContextEnricher { @@ -71,6 +72,11 @@ public abstract class RangerAbstractContextEnricher implements RangerContextEnri } @Override + public void enrich(RangerAccessRequest request, Object dataStore) { + enrich(request); + } + + @Override public boolean preCleanup() { return true; } http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerContextEnricher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerContextEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerContextEnricher.java index 9d0b985..d39c030 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerContextEnricher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerContextEnricher.java @@ -37,6 +37,8 @@ public interface RangerContextEnricher { void enrich(RangerAccessRequest request); + void enrich(RangerAccessRequest request, Object dataStore); + boolean preCleanup(); void cleanup(); http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java ---------------------------------------------------------------------- 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 d5d14a2..83d1280 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 @@ -36,6 +36,8 @@ import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessResource; import org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; +import org.apache.ranger.plugin.service.RangerAuthContext; +import org.apache.ranger.plugin.service.RangerBasePlugin; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.RangerPerfTracer; import org.apache.ranger.plugin.util.RangerResourceTrie; @@ -142,15 +144,38 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher { LOG.debug("==> RangerTagEnricher.enrich(" + request + ")"); } - final Set<RangerTagForEval> matchedTags = enrichedServiceTags == null ? null : findMatchingTags(request); + enrich(request, null); + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerTagEnricher.enrich(" + request + ")"); + } + } + + @Override + public void enrich(RangerAccessRequest request, Object dataStore) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerTagEnricher.enrich(" + request + ") with dataStore:[" + dataStore + "]"); + } + final EnrichedServiceTags enrichedServiceTags; + + if (dataStore instanceof EnrichedServiceTags) { + enrichedServiceTags = (EnrichedServiceTags) dataStore; + } else { + enrichedServiceTags = this.enrichedServiceTags; + + if (dataStore != null) { + LOG.warn("Incorrect type of dataStore :[" + dataStore.getClass().getName() + "], falling back to original enrich"); + } + } + + final Set<RangerTagForEval> matchedTags = enrichedServiceTags == null ? null : findMatchingTags(request, enrichedServiceTags); RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), matchedTags); if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerTagEnricher.enrich(" + request + "): tags count=" + (matchedTags == null ? 0 : matchedTags.size())); + LOG.debug("<== RangerTagEnricher.enrich(" + request + ") with dataStore:[" + dataStore + "]): tags count=" + (matchedTags == null ? 0 : matchedTags.size())); } } - /* * This class implements a cache of result of look-up of keyset of policy-resources for each of the collections of hierarchies * for policy types: access, datamask and rowfilter. If a keyset is examined for validity in a hierarchy of a policy-type, @@ -266,6 +291,16 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher { } enrichedServiceTags = new EnrichedServiceTags(serviceTags, resourceMatchers, serviceResourceTrie, tagsForEmptyResourceAndAnyAccess); + + Map<String, RangerBasePlugin> servicePluginMap = RangerBasePlugin.getServicePluginMap(); + RangerBasePlugin plugin = servicePluginMap != null ? servicePluginMap.get(getServiceName()) : null; + if (plugin != null) { + RangerAuthContext currentAuthContext = plugin.getCurrentRangerAuthContext(); + if (currentAuthContext != null) { + currentAuthContext.addOrReplaceRequestContextEnricher(this, enrichedServiceTags); + plugin.contextChanged(); + } + } } } @@ -292,13 +327,13 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher { return ret; } - private Set<RangerTagForEval> findMatchingTags(final RangerAccessRequest request) { + private Set<RangerTagForEval> findMatchingTags(final RangerAccessRequest request, EnrichedServiceTags dataStore) { if (LOG.isDebugEnabled()) { LOG.debug("==> RangerTagEnricher.findMatchingTags(" + request + ")"); } // To minimize chance for race condition between Tag-Refresher thread and access-evaluation thread - final EnrichedServiceTags enrichedServiceTags = this.enrichedServiceTags; + final EnrichedServiceTags enrichedServiceTags = dataStore != null ? dataStore : this.enrichedServiceTags; Set<RangerTagForEval> ret = null; http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java ---------------------------------------------------------------------- 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 3b06f42..5dcdd59 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 @@ -174,7 +174,7 @@ public class RangerAccessRequestImpl implements RangerAccessRequest { } public void setAccessTime(Date accessTime) { - this.accessTime = (accessTime == null) ? new Date() : accessTime; + this.accessTime = accessTime; } public void setClientIPAddress(String ipAddress) { http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java index 313a8a9..085251a 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java @@ -57,6 +57,8 @@ public interface RangerPolicyEngine { Collection<RangerAccessResult> evaluatePolicies(Collection<RangerAccessRequest> requests, int policyType, RangerAccessResultProcessor resultProcessor); + RangerResourceACLs getResourceACLs(RangerAccessRequest request); + boolean preCleanup(); void cleanup(); @@ -75,6 +77,8 @@ public interface RangerPolicyEngine { List<RangerPolicy> getMatchingPolicies(RangerAccessResource resource); + List<RangerPolicy> getMatchingPolicies(RangerAccessRequest request); + RangerResourceAccessInfo getResourceAccessInfo(RangerAccessRequest request); List<RangerPolicy> getAllowedPolicies(String user, Set<String> userGroups, String accessType); http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java ---------------------------------------------------------------------- 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 5510f6e..5bce47b 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 @@ -31,6 +31,7 @@ import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; +import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.PolicyACLSummary; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.RangerPerfTracer; @@ -41,10 +42,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_CONDITIONAL; + public class RangerPolicyEngineImpl implements RangerPolicyEngine { private static final Log LOG = LogFactory.getLog(RangerPolicyEngineImpl.class); @@ -54,6 +58,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { private static final Log PERF_CONTEXTENRICHER_REQUEST_LOG = RangerPerfTracer.getPerfLogger("contextenricher.request"); private static final Log PERF_POLICYENGINE_REBALANCE_LOG = RangerPerfTracer.getPerfLogger("policyengine.rebalance"); private static final Log PERF_POLICYENGINE_USAGE_LOG = RangerPerfTracer.getPerfLogger("policyengine.usage"); + private static final Log PERF_POLICYENGINE_GET_ACLS_LOG = RangerPerfTracer.getPerfLogger("policyengine.getResourceACLs"); private static final int MAX_POLICIES_FOR_CACHE_TYPE_EVALUATOR = 100; @@ -326,6 +331,130 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { } @Override + public RangerResourceACLs getResourceACLs(RangerAccessRequest request) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.getResourceACLs(request=" + request + ")"); + } + + RangerPerfTracer perf = null; + + if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_GET_ACLS_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_GET_ACLS_LOG, "RangerPolicyEngine.getResourceACLs(requestHashCode=" + request.getResource().getAsString() + ")"); + } + + RangerResourceACLs ret = new RangerResourceACLs(); + Set<RangerTagForEval> tags = RangerAccessRequestUtil.getRequestTagsFromContext(request.getContext()); + List<PolicyEvaluatorForTag> tagPolicyEvaluators = tagPolicyRepository == null ? null : tagPolicyRepository.getLikelyMatchPolicyEvaluators(tags, RangerPolicy.POLICY_TYPE_ACCESS, null); + List<RangerPolicyEvaluator> resourcePolicyEvaluators = policyRepository.getLikelyMatchPolicyEvaluators(request.getResource(), RangerPolicy.POLICY_TYPE_ACCESS); + List<RangerPolicyEvaluator> allEvaluators; + Map<Long, RangerPolicyResourceMatcher.MatchType> tagMatchTypeMap = null; + Set<Long> policyIdForTemporalTags = null; + + if (CollectionUtils.isNotEmpty(tagPolicyEvaluators)) { + allEvaluators = new ArrayList<>(); + tagMatchTypeMap = new HashMap<>(); + + for (PolicyEvaluatorForTag tagEvaluator : tagPolicyEvaluators) { + RangerPolicyEvaluator evaluator = tagEvaluator.getEvaluator(); + RangerTagForEval tag = tagEvaluator.getTag(); + + allEvaluators.add(evaluator); + tagMatchTypeMap.put(evaluator.getId(), tag.getMatchType()); + + if (CollectionUtils.isNotEmpty(tag.getValidityPeriods())) { + if (policyIdForTemporalTags == null) { + policyIdForTemporalTags = new HashSet<>(); + } + + policyIdForTemporalTags.add(evaluator.getId()); + } + } + + allEvaluators.addAll(resourcePolicyEvaluators); + allEvaluators.sort(RangerPolicyEvaluator.EVAL_ORDER_COMPARATOR); + } else { + allEvaluators = resourcePolicyEvaluators; + } + + if (CollectionUtils.isNotEmpty(allEvaluators)) { + Integer policyPriority = null; + + for (RangerPolicyEvaluator evaluator : allEvaluators) { + if (policyPriority == null) { + policyPriority = evaluator.getPolicyPriority(); + } + + if (policyPriority != evaluator.getPolicyPriority()) { + ret.finalizeAcls(); + + policyPriority = evaluator.getPolicyPriority(); + } + + RangerPolicyResourceMatcher.MatchType matchType = tagMatchTypeMap != null ? tagMatchTypeMap.get(evaluator.getId()) : null; + + if (matchType == null) { + // This evaluator is not tag evaluator + matchType = evaluator.getPolicyResourceMatcher().getMatchType(request.getResource(), request.getContext()); + if (matchType == RangerPolicyResourceMatcher.MatchType.DESCENDANT) { + // Need to skip this evaluator, if access-type were not ANY, in RangerDefaultPolicyEvaluator this will cause + // the evaluation to be skipped + continue; + } + } + + PolicyACLSummary aclSummary = evaluator.getPolicyACLSummary(); + + if (aclSummary != null) { + + boolean isConditional = (policyIdForTemporalTags != null && policyIdForTemporalTags.contains(evaluator.getId())) || evaluator.getValidityScheduleEvaluatorsCount() != 0; + + Integer accessResult; + for (Map.Entry<String, Map<String, PolicyACLSummary.AccessResult>> userAccessInfo : aclSummary.getUsersAccessInfo().entrySet()) { + final String userName = userAccessInfo.getKey(); + + for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : userAccessInfo.getValue().entrySet()) { + if (isConditional) { + accessResult = ACCESS_CONDITIONAL; + } else { + accessResult = accessInfo.getValue().getResult(); + if (accessResult.equals(RangerPolicyEvaluator.ACCESS_UNDETERMINED)) { + accessResult = RangerPolicyEvaluator.ACCESS_DENIED; + } + } + ret.setUserAccessInfo(userName, accessInfo.getKey(), accessResult); + } + } + + for (Map.Entry<String, Map<String, PolicyACLSummary.AccessResult>> groupAccessInfo : aclSummary.getGroupsAccessInfo().entrySet()) { + final String groupName = groupAccessInfo.getKey(); + + for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : groupAccessInfo.getValue().entrySet()) { + if (isConditional) { + accessResult = ACCESS_CONDITIONAL; + } else { + accessResult = accessInfo.getValue().getResult(); + if (accessResult.equals(RangerPolicyEvaluator.ACCESS_UNDETERMINED)) { + accessResult = RangerPolicyEvaluator.ACCESS_DENIED; + } + } + ret.setGroupAccessInfo(groupName, accessInfo.getKey(), accessResult); + } + } + } + } + ret.finalizeAcls(); + } + + RangerPerfTracer.logAlways(perf); + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.getResourceACLs(request=" + request + ") : ret=" + ret); + } + + return ret; + } + + @Override public boolean preCleanup() { boolean ret = true; @@ -551,12 +680,27 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { LOG.debug("==> RangerPolicyEngineImpl.getMatchingPolicies(" + resource + ")"); } - List<RangerPolicy> ret = new ArrayList<>(); - RangerAccessRequestImpl request = new RangerAccessRequestImpl(resource, RangerPolicyEngine.ANY_ACCESS, null, null); preProcess(request); + List<RangerPolicy> ret = getMatchingPolicies(request); + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.getMatchingPolicies(" + resource + ") : " + ret.size()); + } + + return ret; + } + + @Override + public List<RangerPolicy> getMatchingPolicies(RangerAccessRequest request) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.getMatchingPolicies(" + request + ")"); + } + + List<RangerPolicy> ret = new ArrayList<>(); + if (hasTagPolicies()) { Set<RangerTagForEval> tags = RangerAccessRequestUtil.getRequestTagsFromContext(request.getContext()); @@ -568,7 +712,8 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { for (RangerPolicyEvaluator evaluator : likelyEvaluators) { RangerPolicyResourceMatcher matcher = evaluator.getPolicyResourceMatcher(); - if (matcher != null && matcher.isMatch(tagResource, RangerPolicyResourceMatcher.MatchScope.ANY, null)) { + if (matcher != null && + (request.isAccessTypeAny() ? matcher.isMatch(tagResource, RangerPolicyResourceMatcher.MatchScope.ANY, null) : matcher.isMatch(tagResource, null))) { ret.add(evaluator.getPolicy()); } } @@ -578,11 +723,12 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { } if (hasResourcePolicies()) { - List<RangerPolicyEvaluator> likelyEvaluators = policyRepository.getLikelyMatchPolicyEvaluators(resource); + List<RangerPolicyEvaluator> likelyEvaluators = policyRepository.getLikelyMatchPolicyEvaluators(request.getResource()); for (RangerPolicyEvaluator evaluator : likelyEvaluators) { RangerPolicyResourceMatcher matcher = evaluator.getPolicyResourceMatcher(); - if (matcher != null && matcher.isMatch(resource, RangerPolicyResourceMatcher.MatchScope.ANY, null)) { + if (matcher != null && + (request.isAccessTypeAny() ? matcher.isMatch(request.getResource(), RangerPolicyResourceMatcher.MatchScope.ANY, null) : matcher.isMatch(request.getResource(), null))) { ret.add(evaluator.getPolicy()); } } @@ -590,7 +736,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { } if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerPolicyEngineImpl.getMatchingPolicies(" + resource + ") : " + ret.size()); + LOG.debug("<== RangerPolicyEngineImpl.getMatchingPolicies(" + request + ") : " + ret.size()); } return ret; } http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java index 2bbdced..b76820c 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java @@ -32,6 +32,7 @@ public class RangerPolicyEngineOptions { public boolean cacheAuditResults = true; public boolean evaluateDelegateAdminOnly = false; public boolean enableTagEnricherWithLocalRefresher = false; + public boolean disableAccessEvaluationWithPolicyACLSummary = true; private RangerServiceDefHelper serviceDefHelper; @@ -48,6 +49,7 @@ public class RangerPolicyEngineOptions { } evaluateDelegateAdminOnly = false; enableTagEnricherWithLocalRefresher = false; + disableAccessEvaluationWithPolicyACLSummary = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.access.evaluation.with.policy.acl.summary", true); } public void configureDefaultRangerAdmin(Configuration conf, String propertyPrefix) { @@ -59,6 +61,7 @@ public class RangerPolicyEngineOptions { cacheAuditResults = false; evaluateDelegateAdminOnly = false; enableTagEnricherWithLocalRefresher = false; + disableAccessEvaluationWithPolicyACLSummary = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.access.evaluation.with.policy.acl.summary", true); } public void configureDelegateAdmin(Configuration conf, String propertyPrefix) { http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java new file mode 100644 index 0000000..34098fa --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java @@ -0,0 +1,233 @@ +/* + * 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.policyengine; + +import org.apache.commons.lang.StringUtils; +import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; +import org.codehaus.jackson.annotate.JsonAutoDetect; +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_DENIED; + +public class RangerResourceACLs { + final private Map<String, Map<String, AccessResult>> userACLs = new HashMap<>(); + final private Map<String, Map<String, AccessResult>> groupACLs = new HashMap<>(); + + public RangerResourceACLs() { + } + + public Map<String, Map<String, AccessResult>> getUserACLs() { + return userACLs; + } + + public Map<String, Map<String, AccessResult>> getGroupACLs() { + return groupACLs; + } + + public void finalizeAcls() { + Map<String, AccessResult> publicGroupAccessInfo = groupACLs.get(RangerPolicyEngine.GROUP_PUBLIC); + if (publicGroupAccessInfo != null) { + + for (Map.Entry<String, AccessResult> entry : publicGroupAccessInfo.entrySet()) { + String accessType = entry.getKey(); + AccessResult accessResult = entry.getValue(); + int access = accessResult.getResult(); + + if (access == RangerPolicyEvaluator.ACCESS_DENIED || access == RangerPolicyEvaluator.ACCESS_ALLOWED) { + for (Map.Entry<String, Map<String, AccessResult>> mapEntry : userACLs.entrySet()) { + Map<String, AccessResult> mapValue = mapEntry.getValue(); + AccessResult savedAccessResult = mapValue.get(accessType); + if (savedAccessResult != null && !savedAccessResult.getIsFinal()) { + mapValue.remove(accessType); + } + } + + for (Map.Entry<String, Map<String, AccessResult>> mapEntry : groupACLs.entrySet()) { + if (!StringUtils.equals(mapEntry.getKey(), RangerPolicyEngine.GROUP_PUBLIC)) { + Map<String, AccessResult> mapValue = mapEntry.getValue(); + AccessResult savedAccessResult = mapValue.get(accessType); + if (savedAccessResult != null && !savedAccessResult.getIsFinal()) { + mapValue.remove(accessType); + } + } + } + } + } + } + finalizeAcls(userACLs); + finalizeAcls(groupACLs); + } + + public void setUserAccessInfo(String userName, String accessType, Integer access) { + Map<String, AccessResult> userAccessInfo = userACLs.get(userName); + + if (userAccessInfo == null) { + userAccessInfo = new HashMap<>(); + + userACLs.put(userName, userAccessInfo); + } + + AccessResult accessResult = userAccessInfo.get(accessType); + + if (accessResult == null) { + accessResult = new AccessResult(access); + + userAccessInfo.put(accessType, accessResult); + } else { + accessResult.setResult(access); + } + } + + public void setGroupAccessInfo(String groupName, String accessType, Integer access) { + Map<String, AccessResult> groupAccessInfo = groupACLs.get(groupName); + + if (groupAccessInfo == null) { + groupAccessInfo = new HashMap<>(); + + groupACLs.put(groupName, groupAccessInfo); + } + + AccessResult accessResult = groupAccessInfo.get(accessType); + + if (accessResult == null) { + accessResult = new AccessResult(access); + + groupAccessInfo.put(accessType, accessResult); + } else { + accessResult.setResult(access); + } + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("{"); + sb.append("UserACLs={"); + for (Map.Entry<String, Map<String, AccessResult>> entry : userACLs.entrySet()) { + sb.append("user=").append(entry.getKey()).append(":"); + sb.append("permissions={"); + for (Map.Entry<String, AccessResult> permission : entry.getValue().entrySet()) { + sb.append("{Permission=").append(permission.getKey()).append(", value=").append(permission.getValue()).append("},"); + } + sb.append("},"); + } + sb.append("}"); + sb.append(", GroupACLs={"); + for (Map.Entry<String, Map<String, AccessResult>> entry : groupACLs.entrySet()) { + sb.append("group=").append(entry.getKey()).append(":"); + sb.append("permissions={"); + for (Map.Entry<String, AccessResult> permission : entry.getValue().entrySet()) { + sb.append("{Permission=").append(permission.getKey()).append(", value=").append(permission.getValue()).append("}, "); + } + sb.append("},"); + } + sb.append("}"); + sb.append("}"); + + return sb.toString(); + } + + private void finalizeAcls(Map<String, Map<String, AccessResult>> acls) { + List<String> keysToRemove = new ArrayList<>(); + for (Map.Entry<String, Map<String, AccessResult>> entry : acls.entrySet()) { + if (entry.getValue().isEmpty()) { + keysToRemove.add(entry.getKey()); + } else { + for (Map.Entry<String, AccessResult> permission : entry.getValue().entrySet()) { + permission.getValue().setIsFinal(true); + } + } + + } + for (String keyToRemove : keysToRemove) { + acls.remove(keyToRemove); + } + } + + @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY) + @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) + @JsonIgnoreProperties(ignoreUnknown=true) + @XmlRootElement + @XmlAccessorType(XmlAccessType.FIELD) + public static class AccessResult { + private int result; + private boolean isFinal; + + + public AccessResult() { + this(-1); + } + + public AccessResult(int result) { + this(result, false); + } + + public AccessResult(int result, boolean isFinal) { + setIsFinal(isFinal); + setResult(result); + } + + public int getResult() { return result; } + + public void setResult(int result) { + if (!isFinal) { + this.result = result; + + if (this.result == ACCESS_DENIED) { + isFinal = true; + } + } + } + + public boolean getIsFinal() { return isFinal; } + + public void setIsFinal(boolean isFinal) { this.isFinal = isFinal; } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + if (other instanceof AccessResult) { + AccessResult otherObject = (AccessResult)other; + return result == otherObject.result && isFinal == otherObject.isFinal; + } else + return false; + + } + @Override + public String toString() { + if (result == RangerPolicyEvaluator.ACCESS_ALLOWED) + return "ALLOWED, final=" + isFinal; + if (result == RangerPolicyEvaluator.ACCESS_DENIED) + return "NOT_ALLOWED, final=" + isFinal; + return "CONDITIONAL_ALLOWED, final=" + isFinal; + } + } +} http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java index 4e6ca2f..bc459e3 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java @@ -135,6 +135,9 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu } @Override + public PolicyACLSummary getPolicyACLSummary() { return null; } + + @Override public String toString( ) { StringBuilder sb = new StringBuilder(); http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyItemEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyItemEvaluator.java index cd7c3c1..f58d514 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyItemEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyItemEvaluator.java @@ -35,7 +35,7 @@ public abstract class RangerAbstractPolicyItemEvaluator implements RangerPolicyI private static final int RANGER_POLICY_ITEM_EVAL_ORDER_DEFAULT = 1000; - private static final int RANGER_POLICY_ITEM_EVAL_ORDER_MAX_DISCOUNT_USERSGROUPS = 25; + private static final int RANGER_POLICY_ITEM_EVAL_ORDER_MAX_DISCOUNT_USERSGROUPS = 100; private static final int RANGER_POLICY_ITEM_EVAL_ORDER_MAX_DISCOUNT_ACCESS_TYPES = 25; private static final int RANGER_POLICY_ITEM_EVAL_ORDER_MAX_DISCOUNT_CUSTOM_CONDITIONS = 25; private static final int RANGER_POLICY_ITEM_EVAL_ORDER_CUSTOM_CONDITION_PENALTY = 5; http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java ---------------------------------------------------------------------- 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 c539cc0..63fc468 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 @@ -45,6 +45,7 @@ import org.apache.ranger.plugin.model.RangerValiditySchedule; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessResource; import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; import org.apache.ranger.plugin.policyengine.RangerResourceAccessInfo; import org.apache.ranger.plugin.policyengine.RangerTagAccessRequest; @@ -60,6 +61,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator private static final Log LOG = LogFactory.getLog(RangerDefaultPolicyEvaluator.class); private static final Log PERF_POLICY_INIT_LOG = RangerPerfTracer.getPerfLogger("policy.init"); + private static final Log PERF_POLICY_INIT_ACLSUMMARY_LOG = RangerPerfTracer.getPerfLogger("policy.init.ACLSummary"); private static final Log PERF_POLICY_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policy.request"); private RangerPolicyResourceMatcher resourceMatcher; @@ -71,8 +73,9 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator private int customConditionsCount; private List<RangerDataMaskPolicyItemEvaluator> dataMaskEvaluators; private List<RangerRowFilterPolicyItemEvaluator> rowFilterEvaluators; - private String perfTag; + private PolicyACLSummary aclSummary = null; + private boolean useAclSummaryForEvaluation = false; protected boolean needsDynamicEval() { return resourceMatcher != null && resourceMatcher.getNeedsDynamicEval(); } @@ -82,6 +85,11 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator } @Override + public int getValidityScheduleEvaluatorsCount() { + return validityScheduleEvaluators.size(); + } + + @Override public RangerPolicyResourceMatcher getPolicyResourceMatcher() { return resourceMatcher; } @Override @@ -121,20 +129,35 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator if(policy != null) { validityScheduleEvaluators = createValidityScheduleEvaluators(policy); - allowEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW); - denyEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY); - allowExceptionEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS); - denyExceptionEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS); - dataMaskEvaluators = createDataMaskPolicyItemEvaluators(policy, serviceDef, options, policy.getDataMaskPolicyItems()); - rowFilterEvaluators = createRowFilterPolicyItemEvaluators(policy, serviceDef, options, policy.getRowFilterPolicyItems()); + + if (!options.disableAccessEvaluationWithPolicyACLSummary) { + aclSummary = createPolicyACLSummary(); + } + + useAclSummaryForEvaluation = aclSummary != null; + + if (useAclSummaryForEvaluation) { + allowEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + denyEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + allowExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + denyExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + } else { + allowEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW); + denyEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY); + allowExceptionEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS); + denyExceptionEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS); + } + + dataMaskEvaluators = createDataMaskPolicyItemEvaluators(policy, serviceDef, options, policy.getDataMaskPolicyItems()); + rowFilterEvaluators = createRowFilterPolicyItemEvaluators(policy, serviceDef, options, policy.getRowFilterPolicyItems()); } else { validityScheduleEvaluators = Collections.<RangerValidityScheduleEvaluator>emptyList(); - allowEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - denyEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - allowExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - denyExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - dataMaskEvaluators = Collections.<RangerDataMaskPolicyItemEvaluator>emptyList(); - rowFilterEvaluators = Collections.<RangerRowFilterPolicyItemEvaluator>emptyList(); + allowEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + denyEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + allowExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + denyExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); + dataMaskEvaluators = Collections.<RangerDataMaskPolicyItemEvaluator>emptyList(); + rowFilterEvaluators = Collections.<RangerRowFilterPolicyItemEvaluator>emptyList(); } RangerPolicyItemEvaluator.EvalOrderComparator comparator = new RangerPolicyItemEvaluator.EvalOrderComparator(); @@ -362,7 +385,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator @Override public void getResourceAccessInfo(RangerAccessRequest request, RangerResourceAccessInfo result) { - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultPolicyEvaluator.getResourceAccessInfo(" + request + ", " + result + ")"); } RangerPolicyResourceMatcher.MatchType matchType; @@ -418,20 +441,156 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator } } - if(LOG.isDebugEnabled()) { + if (LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultPolicyEvaluator.getResourceAccessInfo(" + request + ", " + result + ")"); } } + /* + This API is called by policy-engine to support components which need to statically determine Ranger ACLs + for a given resource. It will always return a non-null object. The accesses that cannot be determined + statically will be marked as CONDITIONAL. + */ + + @Override + public PolicyACLSummary getPolicyACLSummary() { + if (aclSummary == null) { + boolean forceCreation = true; + aclSummary = createPolicyACLSummary(forceCreation); + } + + return aclSummary; + } + + void updateAccessResult(RangerAccessResult result, RangerPolicyResourceMatcher.MatchType matchType, boolean isAllowed) { + if(!isAllowed) { + if(matchType != RangerPolicyResourceMatcher.MatchType.DESCENDANT) { + result.setIsAllowed(false); + result.setPolicyPriority(getPolicy().getPolicyPriority()); + result.setPolicyId(getId()); + //result.setReason(getComments()); + } + } else { + if(! result.getIsAllowed()) { // if access is not yet allowed by another policy + result.setIsAllowed(true); + result.setPolicyPriority(getPolicy().getPolicyPriority()); + result.setPolicyId(getId()); + //result.setReason(getComments()); + } + } + } + + /* + This API is only called during initialization of Policy Evaluator if policy-engine is configured to use + PolicyACLSummary for access evaluation (that is, if disableAccessEvaluationWithPolicyACLSummary option + is set to false). It may return null object if all accesses for all user/groups cannot be determined statically. + */ + + private PolicyACLSummary createPolicyACLSummary() { + boolean forceCreation = false; + return createPolicyACLSummary(forceCreation); + } + + private PolicyACLSummary createPolicyACLSummary(boolean isCreationForced) { + PolicyACLSummary ret = null; + RangerPerfTracer perf = null; + + if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_INIT_ACLSUMMARY_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_INIT_ACLSUMMARY_LOG, "RangerPolicyEvaluator.init.ACLSummary(" + perfTag + ")"); + } + + final boolean hasNonPublicGroupOrConditionsInAllowExceptions = hasNonPublicGroupOrConditions(getPolicy().getAllowExceptions()); + final boolean hasNonPublicGroupOrConditionsInDenyExceptions = hasNonPublicGroupOrConditions(getPolicy().getDenyExceptions()); + final boolean hasPublicGroupInAllowAndUsersInAllowExceptions = hasPublicGroupAndUserInException(getPolicy().getPolicyItems(), getPolicy().getAllowExceptions()); + final boolean hasPublicGroupInDenyAndUsersInDenyExceptions = hasPublicGroupAndUserInException(getPolicy().getDenyPolicyItems(), getPolicy().getDenyExceptions()); + final boolean hasContextSensitiveSpecification = hasContextSensitiveSpecification(); + final boolean isUsableForEvaluation = !hasNonPublicGroupOrConditionsInAllowExceptions + && !hasNonPublicGroupOrConditionsInDenyExceptions + && !hasPublicGroupInAllowAndUsersInAllowExceptions + && !hasPublicGroupInDenyAndUsersInDenyExceptions + && !hasContextSensitiveSpecification; + + if (isUsableForEvaluation || isCreationForced) { + ret = new PolicyACLSummary(); + + for (RangerPolicyItem policyItem : getPolicy().getDenyPolicyItems()) { + ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY, hasNonPublicGroupOrConditionsInDenyExceptions || hasPublicGroupInDenyAndUsersInDenyExceptions); + } + + if (!hasNonPublicGroupOrConditionsInDenyExceptions && !hasPublicGroupInDenyAndUsersInDenyExceptions) { + for (RangerPolicyItem policyItem : getPolicy().getDenyExceptions()) { + ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS, false); + } + } + + for (RangerPolicyItem policyItem : getPolicy().getPolicyItems()) { + ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW, hasNonPublicGroupOrConditionsInAllowExceptions || hasPublicGroupInAllowAndUsersInAllowExceptions); + } + + if (!hasNonPublicGroupOrConditionsInAllowExceptions && !hasPublicGroupInAllowAndUsersInAllowExceptions) { + for (RangerPolicyItem policyItem : getPolicy().getAllowExceptions()) { + ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS, false); + } + } + + ret.finalizeAcls(); + } + + RangerPerfTracer.logAlways(perf); + + return ret; + } + + private boolean hasPublicGroupAndUserInException(List<RangerPolicyItem> grants, List<RangerPolicyItem> exceptionItems) { + boolean ret = false; + + if (CollectionUtils.isNotEmpty(exceptionItems)) { + boolean hasPublicGroupInGrant = false; + + for (RangerPolicyItem policyItem : grants) { + if (policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC) || policyItem.getUsers().contains(RangerPolicyEngine.USER_CURRENT)) { + hasPublicGroupInGrant = true; + break; + } + } + + if (hasPublicGroupInGrant) { + boolean hasPublicGroupInException = false; + + for (RangerPolicyItem policyItem : exceptionItems) { + if (policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC) || policyItem.getUsers().contains(RangerPolicyEngine.USER_CURRENT)) { + hasPublicGroupInException = true; + break; + } + } + + if (!hasPublicGroupInException) { + ret = true; + } + } + } + + return ret; + } + protected void evaluatePolicyItems(RangerAccessRequest request, RangerPolicyResourceMatcher.MatchType matchType, RangerAccessResult result) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultPolicyEvaluator.evaluatePolicyItems(" + request + ", " + result + ", " + matchType + ")"); } + if (useAclSummaryForEvaluation && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + LOG.info("Using ACL Summary for access evaluation. PolicyId=[" + getId() +"]"); + Integer accessResult = lookupPolicyACLSummary(request.getUser(), request.getUserGroups(), request.getAccessType()); + if (accessResult != null) { + updateAccessResult(result, matchType, accessResult.equals(RangerPolicyEvaluator.ACCESS_ALLOWED)); + } + } else { + LOG.info("Using policyItemEvaluators for access evaluation. PolicyId=[" + getId() +"]"); - RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(request, result); + RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(request, result); - if(matchedPolicyItem != null) { - matchedPolicyItem.updateAccessResult(result, matchType, getPolicy()); + if (matchedPolicyItem != null) { + matchedPolicyItem.updateAccessResult(result, matchType, getPolicy()); + } } if(LOG.isDebugEnabled()) { @@ -439,6 +598,96 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator } } + private Integer lookupPolicyACLSummary(String user, Set<String> userGroups, String accessType) { + Integer accessResult = null; + + Map<String, PolicyACLSummary.AccessResult> accesses = aclSummary.getUsersAccessInfo().get(user); + + accessResult = lookupAccess(user, accessType, accesses); + + if (accessResult == null) { + + Set<String> groups = new HashSet<>(); + groups.add(RangerPolicyEngine.GROUP_PUBLIC); + groups.addAll(userGroups); + + for (String userGroup : groups) { + accesses = aclSummary.getGroupsAccessInfo().get(userGroup); + accessResult = lookupAccess(userGroup, accessType, accesses); + if (accessResult != null) { + break; + } + } + } + + return accessResult; + } + + private Integer lookupAccess(String userOrGroup, String accessType, Map<String, PolicyACLSummary.AccessResult> accesses) { + Integer ret = null; + if (accesses != null) { + if (accessType.equals(RangerPolicyEngine.ANY_ACCESS)) { + ret = getAccessResultForAnyAccess(accesses); + } else { + PolicyACLSummary.AccessResult accessResult = accesses.get(accessType); + if (accessResult != null) { + if (accessResult.getResult() == RangerPolicyEvaluator.ACCESS_CONDITIONAL) { + LOG.error("Access should not be conditional at this point! user=[" + userOrGroup + "], " + "accessType=[" + accessType + "]"); + } else { + ret = accessResult.getResult(); + } + } + } + } + return ret; + } + + private Integer getAccessResultForAnyAccess(Map<String, PolicyACLSummary.AccessResult> accessses) { + Integer ret = null; + + int allowedAccessCount = 0; + int deniedAccessCount = 0; + int deniedWithException = 0; + int undeterminedAccessCount = 0; + int accessesSize = 0; + + for (Map.Entry<String, PolicyACLSummary.AccessResult> entry : accessses.entrySet()) { + if (StringUtils.equals(entry.getKey(), RangerPolicyEngine.ADMIN_ACCESS)) { + // Dont count admin access if present + continue; + } + PolicyACLSummary.AccessResult accessResult = entry.getValue(); + if (accessResult.getResult() == RangerPolicyEvaluator.ACCESS_ALLOWED) { + allowedAccessCount++; + } else if (accessResult.getResult() == RangerPolicyEvaluator.ACCESS_DENIED) { + deniedAccessCount++; + } else if (accessResult.getResult() == RangerPolicyEvaluator.ACCESS_UNDETERMINED) { + if (accessResult.getHasSeenDeny()) { + deniedWithException++; + } else { + undeterminedAccessCount++; + } + } + accessesSize++; + } + + int accessTypeCount = getServiceDef().getAccessTypes().size(); + + if (accessTypeCount == accessesSize) { + // All permissions are represented + if (deniedAccessCount > 0 || undeterminedAccessCount == accessTypeCount) { + // at least one is denied or all are undetermined + ret = RangerPolicyEvaluator.ACCESS_DENIED; + } + } + if (ret == null) { + if (allowedAccessCount > 0 || undeterminedAccessCount > 0) { + ret = RangerPolicyEvaluator.ACCESS_ALLOWED; + } + } + return ret; + } + protected RangerPolicyItemEvaluator getDeterminingPolicyItem(String user, Set<String> userGroups, String accessType) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultPolicyEvaluator.getDeterminingPolicyItem(" + user + ", " + userGroups + ", " + accessType + ")"); @@ -528,10 +777,21 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.isAccessAllowed(hashCode=" + Integer.toHexString(System.identityHashCode(this)) + "," + perfTag + ")"); } - RangerPolicyItemEvaluator item = this.getDeterminingPolicyItem(user, userGroups, accessType); + if (useAclSummaryForEvaluation && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + LOG.info("Using ACL Summary for checking if access is allowed. PolicyId=[" + getId() +"]"); - if(item != null && item.getPolicyItemType() == RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW) { - ret = true; + Integer accessResult = lookupPolicyACLSummary(user, userGroups, accessType); + if (accessResult != null && accessResult.equals(RangerPolicyEvaluator.ACCESS_ALLOWED)) { + ret = true; + } + } else { + LOG.info("Using policyItemEvaluators for checking if access is allowed. PolicyId=[" + getId() +"]"); + + RangerPolicyItemEvaluator item = this.getDeterminingPolicyItem(user, userGroups, accessType); + + if (item != null && item.getPolicyItemType() == RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW) { + ret = true; + } } RangerPerfTracer.log(perf); @@ -774,6 +1034,22 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator return ret; } + private static boolean hasNonPublicGroupOrConditions(List<RangerPolicyItem> policyItems) { + boolean ret = false; + for (RangerPolicyItem policyItem : policyItems) { + if (CollectionUtils.isNotEmpty(policyItem.getConditions())) { + ret = true; + break; + } + List<String> allGroups = policyItem.getGroups(); + if (CollectionUtils.isNotEmpty(allGroups) && !allGroups.contains(RangerPolicyEngine.GROUP_PUBLIC)) { + ret = true; + break; + } + } + return ret; + } + protected RangerPolicyItemEvaluator getMatchingPolicyItem(RangerAccessRequest request, RangerAccessResult result) { RangerPolicyItemEvaluator ret = null; @@ -887,5 +1163,4 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator return ret; } - } http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java index 613a001..e3cd154 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java @@ -21,27 +21,45 @@ package org.apache.ranger.plugin.policyevaluator; import java.io.Serializable; +import java.util.ArrayList; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessResult; import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; import org.apache.ranger.plugin.policyengine.RangerResourceAccessInfo; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceEvaluator; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS; public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator { Comparator<RangerPolicyEvaluator> EVAL_ORDER_COMPARATOR = new RangerPolicyEvaluator.PolicyEvalOrderComparator(); Comparator<RangerPolicyEvaluator> NAME_COMPARATOR = new RangerPolicyEvaluator.PolicyNameComparator(); - String EVALUATOR_TYPE_AUTO = "auto"; + // computation of PolicyACLSummary rely on following specific values + Integer ACCESS_DENIED = -1; + Integer ACCESS_UNDETERMINED = 0; + Integer ACCESS_ALLOWED = 1; + Integer ACCESS_CONDITIONAL = 2; + + String EVALUATOR_TYPE_AUTO = "auto"; String EVALUATOR_TYPE_OPTIMIZED = "optimized"; String EVALUATOR_TYPE_CACHED = "cached"; @@ -71,6 +89,8 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator { int getCustomConditionsCount(); + int getValidityScheduleEvaluatorsCount(); + boolean isAuditEnabled(); void evaluate(RangerAccessRequest request, RangerAccessResult result); @@ -89,6 +109,38 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator { void getResourceAccessInfo(RangerAccessRequest request, RangerResourceAccessInfo result); + PolicyACLSummary getPolicyACLSummary(); + + default boolean hasContextSensitiveSpecification() { + RangerPolicy policy = getPolicy(); + + for (RangerPolicyItem policyItem : policy.getPolicyItems()) { + if (hasContextSensitiveSpecification(policyItem)) { + return true; + } + } + for (RangerPolicyItem policyItem : policy.getDenyPolicyItems()) { + if (hasContextSensitiveSpecification(policyItem)) { + return true; + } + } + for (RangerPolicyItem policyItem : policy.getAllowExceptions()) { + if (hasContextSensitiveSpecification(policyItem)) { + return true; + } + } + for (RangerPolicyItem policyItem : policy.getDenyExceptions()) { + if (hasContextSensitiveSpecification(policyItem)) { + return true; + } + } + return false; + } + + static boolean hasContextSensitiveSpecification(RangerPolicyItem policyItem) { + return CollectionUtils.isNotEmpty(policyItem.getConditions()) || policyItem.getUsers().contains(RangerPolicyEngine.RESOURCE_OWNER); /* || policyItem.getGroups().contains(RangerPolicyEngine.RESOURCE_GROUP_OWNER) */ + } + class PolicyEvalOrderComparator implements Comparator<RangerPolicyEvaluator>, Serializable { @Override public int compare(RangerPolicyEvaluator me, RangerPolicyEvaluator other) { @@ -139,4 +191,260 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator { } } + class PolicyACLSummary { + private final Map<String, Map<String, AccessResult>> usersAccessInfo = new HashMap<>(); + private final Map<String, Map<String, AccessResult>> groupsAccessInfo = new HashMap<>(); + + private enum AccessorType { USER, GROUP } + + public static class AccessResult { + private int result; + private final boolean hasSeenDeny; + + public AccessResult(int result) { + this(result, false); + } + + public AccessResult(int result, boolean hasSeenDeny) { + this.hasSeenDeny = hasSeenDeny; + setResult(result); + } + + public int getResult() { + return result; + } + + public void setResult(int result) { + this.result = result; + } + + public boolean getHasSeenDeny() { + return hasSeenDeny; + } + @Override + public String toString() { + if (result == RangerPolicyEvaluator.ACCESS_ALLOWED) + return "ALLOWED, hasSeenDeny=" + hasSeenDeny; + if (result == RangerPolicyEvaluator.ACCESS_DENIED) + return "NOT_ALLOWED, hasSeenDeny=" + hasSeenDeny; + if (result == RangerPolicyEvaluator.ACCESS_CONDITIONAL) + return "CONDITIONAL_ALLOWED, hasSeenDeny=" + hasSeenDeny; + return "NOT_DETERMINED, hasSeenDeny=" + hasSeenDeny; + } + } + + PolicyACLSummary() { + } + + public Map<String, Map<String, AccessResult>> getUsersAccessInfo() { + return usersAccessInfo; + } + + public Map<String, Map<String, AccessResult>> getGroupsAccessInfo() { + return groupsAccessInfo; + } + + void processPolicyItem(RangerPolicyItem policyItem, int policyItemType, boolean isConditional) { + final Integer result; + final boolean hasContextSensitiveSpecification = RangerPolicyEvaluator.hasContextSensitiveSpecification(policyItem); + + switch (policyItemType) { + case POLICY_ITEM_TYPE_ALLOW: + result = (hasContextSensitiveSpecification || isConditional) ? ACCESS_CONDITIONAL : ACCESS_ALLOWED; + break; + + case POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS: + result = (hasContextSensitiveSpecification || isConditional) ? null : ACCESS_DENIED; + break; + + case POLICY_ITEM_TYPE_DENY: + result = (hasContextSensitiveSpecification || isConditional) ? ACCESS_CONDITIONAL : ACCESS_DENIED; + break; + + case POLICY_ITEM_TYPE_DENY_EXCEPTIONS: + result = (hasContextSensitiveSpecification || isConditional) ? null : ACCESS_ALLOWED; + break; + + default: + result = null; + break; + } + + if (result != null) { + final List<RangerPolicyItemAccess> accesses; + + if (policyItem.getDelegateAdmin()) { + accesses = new ArrayList<>(); + + accesses.add(new RangerPolicyItemAccess(RangerPolicyEngine.ADMIN_ACCESS, policyItem.getDelegateAdmin())); + accesses.addAll(policyItem.getAccesses()); + } else { + accesses = policyItem.getAccesses(); + } + + final List<String> groups = policyItem.getGroups(); + final List<String> users = policyItem.getUsers(); + boolean hasPublicGroup = false; + + for (RangerPolicyItemAccess access : accesses) { + for (String user : users) { + if (StringUtils.equals(user, RangerPolicyEngine.USER_CURRENT)) { + hasPublicGroup = true; + continue; + } else if (StringUtils.isBlank(user)) { + continue; + } + + addAccess(user, AccessorType.USER, access.getType(), result, policyItemType); + } + + for (String group : groups) { + if (StringUtils.equals(group, RangerPolicyEngine.GROUP_PUBLIC)) { + hasPublicGroup = true; + continue; + } + + addAccess(group, AccessorType.GROUP, access.getType(), result, policyItemType); + } + + if (hasPublicGroup) { + addAccess(RangerPolicyEngine.GROUP_PUBLIC, AccessorType.GROUP, access.getType(), result, policyItemType); + } + } + } + } + + void finalizeAcls() { + Map<String, AccessResult> publicGroupAccessInfo = groupsAccessInfo.get(RangerPolicyEngine.GROUP_PUBLIC); + + if (publicGroupAccessInfo != null) { + // For each accessType in public, retrieve access + for (Map.Entry<String, AccessResult> entry : publicGroupAccessInfo.entrySet()) { + final String accessType = entry.getKey(); + final AccessResult accessResult = entry.getValue(); + final int access = accessResult.getResult(); + + if (access == ACCESS_DENIED || access == ACCESS_ALLOWED) { + List<String> keysToRemove = null; + + for (Map.Entry<String, Map<String, AccessResult>> mapEntry : usersAccessInfo.entrySet()) { + Map<String, AccessResult> mapValue = mapEntry.getValue(); + + mapValue.remove(accessType); + + if (mapValue.isEmpty()) { + if (keysToRemove == null) { + keysToRemove = new ArrayList<>(); + } + + keysToRemove.add(mapEntry.getKey()); + } + } + + if (keysToRemove != null) { + for (String keyToRemove : keysToRemove) { + usersAccessInfo.remove(keyToRemove); + } + + keysToRemove.clear(); + } + + for (Map.Entry<String, Map<String, AccessResult>> mapEntry : groupsAccessInfo.entrySet()) { + if (!StringUtils.equals(mapEntry.getKey(), RangerPolicyEngine.GROUP_PUBLIC)) { + Map<String, AccessResult> mapValue = mapEntry.getValue(); + + mapValue.remove(accessType); + + if (mapValue.isEmpty()) { + if (keysToRemove == null) { + keysToRemove = new ArrayList<>(); + } + + keysToRemove.add(mapEntry.getKey()); + } + } + } + + + if (keysToRemove != null) { + for (String keyToRemove : keysToRemove) { + groupsAccessInfo.remove(keyToRemove); + } + + keysToRemove.clear(); + } + } + } + + } + } + + private void addAccess(String accessorName, AccessorType accessorType, String accessType, Integer access, int policyItemType) { + final Map<String, Map<String, AccessResult>> accessorsAccessInfo; + + switch (accessorType) { + case USER: + accessorsAccessInfo = usersAccessInfo; + break; + + case GROUP: + accessorsAccessInfo = groupsAccessInfo; + break; + + default: + return; + } + + final Map<String, AccessResult> accessorAccessInfo = accessorsAccessInfo.computeIfAbsent(accessorName, k -> new HashMap<>()); + final AccessResult currentAccess = accessorAccessInfo.get(accessType); + + if (currentAccess == null) { + if (policyItemType == POLICY_ITEM_TYPE_ALLOW || policyItemType == POLICY_ITEM_TYPE_DENY) { + accessorAccessInfo.put(accessType, new AccessResult(access, policyItemType == POLICY_ITEM_TYPE_DENY)); + } + } else { + if (access.equals(RangerPolicyEvaluator.ACCESS_DENIED)) { + if (currentAccess.getResult() == ACCESS_CONDITIONAL) { + currentAccess.setResult(access); + } else { + int updatedAccessValue = currentAccess.getResult() + access; + + if (policyItemType == POLICY_ITEM_TYPE_DENY) { + updatedAccessValue = (updatedAccessValue < ACCESS_DENIED) ? ACCESS_DENIED : updatedAccessValue; + } else { + updatedAccessValue = (updatedAccessValue < ACCESS_UNDETERMINED) ? ACCESS_UNDETERMINED : updatedAccessValue; + } + + currentAccess.setResult(updatedAccessValue); + } + } else if (access.equals(RangerPolicyEvaluator.ACCESS_ALLOWED)) { + if (currentAccess.getResult() == ACCESS_CONDITIONAL) { + if (policyItemType == POLICY_ITEM_TYPE_ALLOW) { + currentAccess.setResult(access); + } + } else { + int updatedAccessValue = currentAccess.getResult() + access; + boolean replaceValue = false; + + if (policyItemType == POLICY_ITEM_TYPE_ALLOW) { + updatedAccessValue = (updatedAccessValue > ACCESS_ALLOWED) ? ACCESS_ALLOWED : updatedAccessValue; + replaceValue = true; // Forget earlier stashed hasSeenDeny + } else { + updatedAccessValue = (updatedAccessValue > ACCESS_UNDETERMINED) ? ACCESS_UNDETERMINED : updatedAccessValue; + } + + if (replaceValue) { + accessorAccessInfo.put(accessType, new AccessResult(updatedAccessValue)); + } else { + currentAccess.setResult(updatedAccessValue); + } + } + } else { + if (currentAccess.getResult() == ACCESS_UNDETERMINED) { + currentAccess.setResult(access); + } + } + } + } + } } http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java index bd61cfd..be0ab7d 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java @@ -67,5 +67,4 @@ public interface RangerPolicyItemEvaluator { } } void updateAccessResult(RangerAccessResult result, RangerPolicyResourceMatcher.MatchType matchType, RangerPolicy policy); - } http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java new file mode 100644 index 0000000..ef7194f --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java @@ -0,0 +1,230 @@ +/* + * 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.service; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.ranger.plugin.contextenricher.RangerContextEnricher; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; +import org.apache.ranger.plugin.policyengine.RangerMutableResource; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; +import org.apache.ranger.plugin.policyengine.RangerResourceAccessInfo; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class RangerAuthContext implements RangerPolicyEngine { + private RangerPolicyEngine policyEngine; + private Map<RangerContextEnricher, Object> requestContextEnrichers; + + protected RangerAuthContext() { + this(null, null); + } + + RangerAuthContext(RangerPolicyEngine policyEngine, Map<RangerContextEnricher, Object> requestContextEnrichers) { + this.policyEngine = policyEngine; + this.requestContextEnrichers = requestContextEnrichers; + } + + RangerAuthContext(RangerAuthContext other) { + if (other != null) { + this.policyEngine = other.getPolicyEngine(); + Map<RangerContextEnricher, Object> localReference = other.requestContextEnrichers; + if (MapUtils.isNotEmpty(localReference)) { + this.requestContextEnrichers = new HashMap<>(localReference); + } + } + } + public RangerPolicyEngine getPolicyEngine() { + return policyEngine; + } + + void setPolicyEngine(RangerPolicyEngine policyEngine) { this.policyEngine = policyEngine; } + + public Map<RangerContextEnricher, Object> getRequestContextEnrichers() { + return requestContextEnrichers; + } + + public void addOrReplaceRequestContextEnricher(RangerContextEnricher enricher, Object database) { + if (requestContextEnrichers == null) { + requestContextEnrichers = new HashMap<>(); + } + + requestContextEnrichers.put(enricher, database); + } + + @Override + public void setUseForwardedIPAddress(boolean useForwardedIPAddress) { + policyEngine.setUseForwardedIPAddress(useForwardedIPAddress); + } + + @Override + public void setTrustedProxyAddresses(String[] trustedProxyAddresses) { + policyEngine.setTrustedProxyAddresses(trustedProxyAddresses); + } + + @Override + public RangerServiceDef getServiceDef() { + return policyEngine.getServiceDef(); + } + + @Override + public long getPolicyVersion() { + return policyEngine.getPolicyVersion(); + } + + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAccessResultProcessor resultProcessor) { + preProcess(requests); + return policyEngine.evaluatePolicies(requests, RangerPolicy.POLICY_TYPE_ACCESS, resultProcessor); + } + + public RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) { + preProcess(request); + return policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, resultProcessor); + } + + public RangerAccessResult evalDataMaskPolicies(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) { + preProcess(request); + return policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_DATAMASK, resultProcessor); + } + + public RangerAccessResult evalRowFilterPolicies(RangerAccessRequest request, RangerAccessResultProcessor resultProcessor) { + preProcess(request); + return policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ROWFILTER, resultProcessor); + } + + @Override + public void preProcess(RangerAccessRequest request) { + + RangerAccessResource resource = request.getResource(); + if (resource.getServiceDef() == null) { + if (resource instanceof RangerMutableResource) { + RangerMutableResource mutable = (RangerMutableResource) resource; + mutable.setServiceDef(getServiceDef()); + } + } + + if (MapUtils.isNotEmpty(requestContextEnrichers)) { + for (Map.Entry<RangerContextEnricher, Object> entry : requestContextEnrichers.entrySet()) { + entry.getKey().enrich(request); + } + } + } + + @Override + public void preProcess(Collection<RangerAccessRequest> requests) { + if (CollectionUtils.isNotEmpty(requests)) { + for (RangerAccessRequest request : requests) { + preProcess(request); + } + } + } + + @Override + public RangerAccessResult evaluatePolicies(RangerAccessRequest request, int policyType, RangerAccessResultProcessor resultProcessor) { + return policyEngine.evaluatePolicies(request, policyType, resultProcessor); + } + + @Override + public Collection<RangerAccessResult> evaluatePolicies(Collection<RangerAccessRequest> requests, int policyType, RangerAccessResultProcessor resultProcessor) { + return policyEngine.evaluatePolicies(requests, policyType, resultProcessor); + } + + @Override + public RangerResourceACLs getResourceACLs(RangerAccessRequest request) { + preProcess(request); + return policyEngine.getResourceACLs(request); + } + + @Override + public boolean preCleanup() { + return policyEngine.preCleanup(); + } + + @Override + public void cleanup() { + policyEngine.cleanup(); + } + + @Override + public RangerResourceAccessInfo getResourceAccessInfo(RangerAccessRequest request) { + preProcess(request); + return policyEngine.getResourceAccessInfo(request); + } + + @Override + public List<RangerPolicy> getMatchingPolicies(RangerAccessResource resource) { + RangerAccessRequestImpl request = new RangerAccessRequestImpl(resource, RangerPolicyEngine.ANY_ACCESS, null, null); + preProcess(request); + return getMatchingPolicies(request); + } + + @Override + public List<RangerPolicy> getMatchingPolicies(RangerAccessRequest request) { + return policyEngine.getMatchingPolicies(request); + } + + /* This API is called for a long running policy-engine. Not needed here */ + @Override + public void reorderPolicyEvaluators() { + } + + /* The following APIs are used only by ranger-admin. Providing dummy implementation */ + @Override + public boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, String accessType) { + return false; + } + + @Override + public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType) { + return false; + } + + @Override + public boolean isAccessAllowed(Map<String, RangerPolicy.RangerPolicyResource> resources, String user, Set<String> userGroups, String accessType) { + return false; + } + + @Override + public List<RangerPolicy> getExactMatchPolicies(Map<String, RangerPolicy.RangerPolicyResource> resources, Map<String, Object> evalContext) { + return null; + } + + @Override + public List<RangerPolicy> getExactMatchPolicies(RangerAccessResource resource, Map<String, Object> evalContext) { + return null; + } + + @Override + public List<RangerPolicy> getAllowedPolicies(String user, Set<String> userGroups, String accessType) { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContextListener.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContextListener.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContextListener.java new file mode 100644 index 0000000..b980552 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContextListener.java @@ -0,0 +1,25 @@ +/* + * 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.service; + + +public interface RangerAuthContextListener { + void contextChanged(); +} http://git-wip-us.apache.org/repos/asf/ranger/blob/3b510f8c/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java index 725ed74..e40d223 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java @@ -25,6 +25,7 @@ import java.util.Hashtable; import java.util.Map; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -55,6 +56,8 @@ public class RangerBasePlugin { public static final char RANGER_TRUSTED_PROXY_IPADDRESSES_SEPARATOR_CHAR = ','; + private static Map<String, RangerBasePlugin> servicePluginMap = new ConcurrentHashMap<>(); + private String serviceType; private String appId; private String serviceName; @@ -62,16 +65,24 @@ public class RangerBasePlugin { private PolicyRefresher refresher; private RangerPolicyEngine policyEngine; private RangerPolicyEngineOptions policyEngineOptions = new RangerPolicyEngineOptions(); + private RangerAuthContext currentAuthContext; + private RangerAuthContext readOnlyAuthContext; private RangerAccessResultProcessor resultProcessor; private boolean useForwardedIPAddress; private String[] trustedProxyAddresses; private Timer policyEngineRefreshTimer; + private RangerAuthContextListener authContextListener; + Map<String, LogHistory> logHistoryList = new Hashtable<String, RangerBasePlugin.LogHistory>(); int logInterval = 30000; // 30 seconds + public static Map<String, RangerBasePlugin> getServicePluginMap() { + return servicePluginMap; + } public RangerBasePlugin(String serviceType, String appId) { + this.serviceType = serviceType; this.appId = appId; } @@ -84,6 +95,12 @@ public class RangerBasePlugin { return clusterName; } + public RangerAuthContext createRangerAuthContext() { + return new RangerAuthContext(readOnlyAuthContext); + } + + public RangerAuthContext getCurrentRangerAuthContext() { return currentAuthContext; } + public void setClusterName(String clusterName) { this.clusterName = clusterName; } @@ -144,6 +161,8 @@ public class RangerBasePlugin { LOG.info(policyEngineOptions); + servicePluginMap.put(serviceName, this); + RangerAdminClient admin = createAdminClient(serviceName, appId, propertyPrefix); refresher = new PolicyRefresher(this, serviceType, appId, serviceName, admin, pollingIntervalMs, cacheDir); @@ -187,13 +206,17 @@ public class RangerBasePlugin { } if (policies == null) { this.policyEngine = null; + readOnlyAuthContext = null; } else { + currentAuthContext = new RangerAuthContext(); RangerPolicyEngine policyEngine = new RangerPolicyEngineImpl(appId, policies, policyEngineOptions); policyEngine.setUseForwardedIPAddress(useForwardedIPAddress); policyEngine.setTrustedProxyAddresses(trustedProxyAddresses); - this.policyEngine = policyEngine; + currentAuthContext.setPolicyEngine(this.policyEngine); + readOnlyAuthContext = new RangerAuthContext(currentAuthContext); } + contextChanged(); if (oldPolicyEngine != null && !oldPolicyEngine.preCleanup()) { LOG.error("preCleanup() failed on the previous policy engine instance !!"); @@ -203,6 +226,14 @@ public class RangerBasePlugin { } } + public void contextChanged() { + RangerAuthContextListener authContextListener = this.authContextListener; + + if (authContextListener != null) { + authContextListener.contextChanged(); + } + } + public void cleanup() { PolicyRefresher refresher = this.refresher; @@ -358,6 +389,13 @@ public class RangerBasePlugin { } } + public void registerAuthContextEventListener(RangerAuthContextListener authContextListener) { + this.authContextListener = authContextListener; + } + public void unregisterAuthContextEventListener(RangerAuthContextListener authContextListener) { + this.authContextListener = null; + } + public static RangerAdminClient createAdminClient(String rangerServiceName, String applicationId, String propertyPrefix) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerBasePlugin.createAdminClient(" + rangerServiceName + ", " + applicationId + ", " + propertyPrefix + ")");