RANGER-1781: Policy model update to support restricted access-types based on selected resource
Signed-off-by: Madhan Neethiraj <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/ranger/commit/7985dd47 Tree: http://git-wip-us.apache.org/repos/asf/ranger/tree/7985dd47 Diff: http://git-wip-us.apache.org/repos/asf/ranger/diff/7985dd47 Branch: refs/heads/master Commit: 7985dd473acb024e8f3c56c12af6608b0cecc3b6 Parents: e0c1e35 Author: Abhay Kulkarni <[email protected]> Authored: Fri Oct 6 08:46:43 2017 -0700 Committer: Madhan Neethiraj <[email protected]> Committed: Tue Oct 10 22:20:24 2017 -0700 ---------------------------------------------------------------------- .../ranger/plugin/model/RangerServiceDef.java | 46 +- .../model/validation/RangerPolicyValidator.java | 16 +- .../validation/RangerServiceDefHelper.java | 126 +- .../RangerDefaultPolicyResourceMatcher.java | 1296 +++++++++--------- .../plugin/service/RangerBaseService.java | 47 +- .../plugin/service/RangerDefaultService.java | 49 + .../ranger/plugin/util/RangerResourceTrie.java | 2 - .../ranger/plugin/util/ServiceDefUtil.java | 52 +- .../validation/TestRangerPolicyValidator.java | 8 +- .../validation/TestRangerServiceDefHelper.java | 114 +- .../model/validation/ValidationTestUtils.java | 1 + .../plugin/policyengine/TestPolicyEngine.java | 6 +- ...stDefaultPolicyResourceMatcherForPolicy.java | 5 +- .../test_defaultpolicyresourcematcher.json | 4 +- ...rcematcher_for_resource_specific_policy.json | 335 +++++ .../ranger/services/hdfs/RangerServiceHdfs.java | 134 +- .../org/apache/ranger/biz/ServiceDBStore.java | 96 +- .../java/org/apache/ranger/biz/ServiceMgr.java | 25 +- .../service/RangerServiceDefServiceBase.java | 58 +- 19 files changed, 1578 insertions(+), 842 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java index ec3ce69..adafb99 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java @@ -22,8 +22,10 @@ package org.apache.ranger.plugin.model; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -1242,9 +1244,11 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S private String rbKeyLabel; private String rbKeyDescription; private String rbKeyValidationMessage; + private Set<String> accessTypeRestrictions; + private Boolean isValidLeaf; public RangerResourceDef() { - this(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + this(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); } public RangerResourceDef(RangerResourceDef other) { @@ -1267,9 +1271,11 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S setRbKeyLabel(other.getRbKeyLabel()); setRbKeyDescription(other.getRbKeyDescription()); setRbKeyValidationMessage(other.getRbKeyValidationMessage()); + setAccessTypeRestrictions(other.getAccessTypeRestrictions()); + setIsValidLeaf(other.getIsValidLeaf()); } - public RangerResourceDef(Long itemId, String name, String type, Integer level, String parent, Boolean mandatory, Boolean lookupSupported, Boolean recursiveSupported, Boolean excludesSupported, String matcher, Map<String, String> matcherOptions, String validationRegEx, String validationMessage, String uiHint, String label, String description, String rbKeyLabel, String rbKeyDescription, String rbKeyValidationMessage) { + public RangerResourceDef(Long itemId, String name, String type, Integer level, String parent, Boolean mandatory, Boolean lookupSupported, Boolean recursiveSupported, Boolean excludesSupported, String matcher, Map<String, String> matcherOptions, String validationRegEx, String validationMessage, String uiHint, String label, String description, String rbKeyLabel, String rbKeyDescription, String rbKeyValidationMessage, Set<String> accessTypeRestrictions, Boolean isValidLeaf) { setItemId(itemId); setName(name); setType(type); @@ -1289,6 +1295,8 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S setRbKeyLabel(rbKeyLabel); setRbKeyDescription(rbKeyDescription); setRbKeyValidationMessage(rbKeyValidationMessage); + setAccessTypeRestrictions(accessTypeRestrictions); + setIsValidLeaf(isValidLeaf); } /** @@ -1557,6 +1565,20 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S this.rbKeyValidationMessage = rbKeyValidationMessage; } + public Set<String> getAccessTypeRestrictions() { + return accessTypeRestrictions; + } + + public void setAccessTypeRestrictions(Set<String> accessTypeRestrictions) { + this.accessTypeRestrictions = accessTypeRestrictions == null ? new HashSet<String>() : new HashSet<String>(accessTypeRestrictions); + } + + public Boolean getIsValidLeaf() { return isValidLeaf; } + + public void setIsValidLeaf(Boolean isValidLeaf) { + this.isValidLeaf = isValidLeaf; + } + @Override public String toString( ) { StringBuilder sb = new StringBuilder(); @@ -1587,6 +1609,8 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S sb.append("rbKeyLabel={").append(rbKeyLabel).append("} "); sb.append("rbKeyDescription={").append(rbKeyDescription).append("} "); sb.append("rbKeyValidationMessage={").append(rbKeyValidationMessage).append("} "); + sb.append("accessTypeRestrictions={").append(accessTypeRestrictions == null ? "null" : accessTypeRestrictions.toString()).append("} "); + sb.append("isValidLeaf={").append(isValidLeaf == null ? "null" : isValidLeaf.toString()).append("} "); sb.append("}"); return sb; @@ -1643,6 +1667,12 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S * result + ((validationRegEx == null) ? 0 : validationRegEx .hashCode()); + result = prime + * result + + ((accessTypeRestrictions == null) ? 0 : accessTypeRestrictions.hashCode()); + result = prime + * result + + ((isValidLeaf == null) ? 0 : isValidLeaf.hashCode()); return result; } @@ -1746,7 +1776,17 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S return false; } else if (!validationRegEx.equals(other.validationRegEx)) return false; - return true; + if (accessTypeRestrictions == null) { + if (other.accessTypeRestrictions != null) + return false; + } else if (!accessTypeRestrictions.equals(other.accessTypeRestrictions)) + return false; + if (isValidLeaf == null) { + if (other.isValidLeaf != null) + return false; + } else if (!isValidLeaf.equals(other.isValidLeaf)) + return false; + return true; } } http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java index 0b5fc0e..95eeca7 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java @@ -461,7 +461,18 @@ public class RangerPolicyValidator extends RangerValidator { RangerServiceDefHelper defHelper = new RangerServiceDefHelper(serviceDef); Set<List<RangerResourceDef>> hierarchies = defHelper.getResourceHierarchies(policy.getPolicyType()); // this can be empty but not null! if (hierarchies.isEmpty()) { - LOG.warn("RangerPolicyValidator.isValidResourceNames: serviceDef does not have any resource hierarchies, possibly due to a old/migrated service def! Skipping this check!"); + if (LOG.isDebugEnabled()) { + LOG.debug("RangerPolicyValidator.isValidResourceNames: serviceDef does not have any resource hierarchies, possibly due to invalid service def!!"); + } + ValidationErrorCode error = ValidationErrorCode.POLICY_VALIDATION_ERR_INVALID_RESOURCE_NO_COMPATIBLE_HIERARCHY; + failures.add(new ValidationFailureDetailsBuilder() + .field("service def resource hierarchies") + .subField("incompatible") + .isSemanticallyIncorrect() + .becauseOf(error.getMessage(serviceDef.getName(), " does not have any resource hierarchies")) + .errorCode(error.getErrorCode()) + .build()); + valid = false; } else { /* * A policy is for a single hierarchy however, it doesn't specify which one. So we have to guess which hierarchy(s) it possibly be for. First, see if the policy could be for @@ -572,8 +583,7 @@ public class RangerPolicyValidator extends RangerValidator { // helper function skipping sanity checks of getting null arguments passed Set<List<RangerResourceDef>> result = new HashSet<List<RangerResourceDef>>(hierarchies.size()); for (List<RangerResourceDef> aHierarchy : hierarchies) { - Set<String> hierarchyResources = defHelper.getAllResourceNames(aHierarchy); - if (hierarchyResources.containsAll(policyResources)) { + if (defHelper.hierarchyHasAllResources(aHierarchy, policyResources)) { result.add(aHierarchy); } } http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java index 9fb724d..7a719ab 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java @@ -179,7 +179,7 @@ public class RangerServiceDefHelper { Set<List<RangerResourceDef>> ret = new HashSet<List<RangerResourceDef>>(); for (List<RangerResourceDef> hierarchy : getResourceHierarchies(policyType)) { - if (getAllResourceNames(hierarchy).containsAll(keys)) { + if (hierarchyHasAllResources(hierarchy, keys)) { ret.add(hierarchy); } } @@ -187,6 +187,28 @@ public class RangerServiceDefHelper { return ret; } + public boolean hierarchyHasAllResources(List<RangerResourceDef> hierarchy, Collection<String> resourceNames) { + boolean foundAllResourceKeys = true; + + for (String resourceKey : resourceNames) { + boolean found = false; + + for (RangerResourceDef resourceDef : hierarchy) { + if (resourceDef.getName().equals(resourceKey)) { + found = true; + break; + } + } + + if (!found) { + foundAllResourceKeys = false; + break; + } + } + + return foundAllResourceKeys; + } + public Set<String> getMandatoryResourceNames(List<RangerResourceDef> hierarchy) { Set<String> result = new HashSet<String>(hierarchy.size()); for (RangerResourceDef resourceDef : hierarchy) { @@ -249,9 +271,10 @@ public class RangerServiceDefHelper { DirectedGraph graph = createGraph(resources); if(graph != null) { - if (isValid(graph)) { - Set<List<String>> hierarchies = getHierarchies(graph); - _hierarchies.put(policyType, Collections.unmodifiableSet(convertHierarchies(hierarchies, getResourcesAsMap(resources)))); + Map<String, RangerResourceDef> resourceDefMap = getResourcesAsMap(resources); + if (isValid(graph, resourceDefMap)) { + Set<List<RangerResourceDef>> hierarchies = getHierarchies(graph, resourceDefMap); + _hierarchies.put(policyType, Collections.unmodifiableSet(hierarchies)); } else { isValid = false; _hierarchies.put(policyType, EMPTY_RESOURCE_HIERARCHY); @@ -266,6 +289,9 @@ public class RangerServiceDefHelper { _serviceDefFreshnessDate == null ? null : _serviceDefFreshnessDate.toString(), _hierarchies); LOG.debug(message); } + if (!_valid) { + LOG.error("ERROR: Service resource-definitions do not form valid DAG!!"); + } } public Set<List<RangerResourceDef>> getResourceHierarchies(Integer policyType) { @@ -357,40 +383,76 @@ public class RangerServiceDefHelper { * * @return */ - boolean isValid(DirectedGraph graph) { - return !graph.getSources().isEmpty() && !graph.getSinks().isEmpty(); - } + boolean isValid(DirectedGraph graph, Map<String, RangerResourceDef> resourceDefMap) { + boolean ret = true; + Set<String> sources = graph.getSources(); + Set<String> sinks = graph.getSinks(); + + if (CollectionUtils.isEmpty(sources) || CollectionUtils.isEmpty(sinks)) { + ret = false; + } else { + for (String sink : sinks) { + RangerResourceDef sinkResourceDef = resourceDefMap.get(sink); + if (Boolean.FALSE.equals(sinkResourceDef.getIsValidLeaf())) { + LOG.error("Error in path: sink node:[" + sink + "] is not leaf node"); + + ret = false; + break; + } else if (sinkResourceDef.getIsValidLeaf() == null) { + LOG.info("Setting sink ResourceDef's isValidLeaf from null to 'true'"); + sinkResourceDef.setIsValidLeaf(true); + } + } + } + + return ret; + } /** * Returns all valid resource hierarchies for the configured resource-defs. Behavior is undefined if it is called on and invalid graph. Use <code>isValid</code> to check validation first. * * @param graph + * @param resourceMap * @return */ - Set<List<String>> getHierarchies(DirectedGraph graph) { - Set<List<String>> hierarchies = new HashSet<>(); - Set<String> sources = graph.getSources(); - Set<String> sinks = graph.getSinks(); - for (String source : sources) { - /* - * A disconnected node, i.e. one that does not have any arc coming into or out of it is a hierarchy in itself! - * A source by definition does not have any arcs coming into it. So if it also doesn't have any neighbors then we know - * it is a disconnected node. - */ - if (!graph.hasNeighbors(source)) { - List<String> path = Lists.newArrayList(source); - hierarchies.add(path); - } else { - for (String sink : sinks) { - List<String> path = graph.getAPath(source, sink, new HashSet<String>()); - if (!path.isEmpty()) { - hierarchies.add(path); - } - } - } - } - return hierarchies; - } + Set<List<RangerResourceDef>> getHierarchies(DirectedGraph graph, Map<String, RangerResourceDef> resourceMap) { + Set<List<String>> hierarchies = new HashSet<>(); + Set<String> sources = graph.getSources(); + Set<String> sinks = graph.getSinks(); + + for (String source : sources) { + /* + * A disconnected node, i.e. one that does not have any arc coming into or out of it is a hierarchy in itself! + * A source by definition does not have any arcs coming into it. So if it also doesn't have any neighbors then we know + * it is a disconnected node. + */ + if (!graph.hasNeighbors(source)) { + hierarchies.add(Lists.newArrayList(source)); + } else { + for (String sink : sinks) { + List<String> path = graph.getAPath(source, sink, new HashSet<String>()); + + if (!path.isEmpty()) { + hierarchies.add(path); + + List<String> workingPath = new ArrayList<String>(); + + for (int index = 0, pathSize = path.size(); index < pathSize -1; index++) { + String node = path.get(index); + + workingPath.add(node); + + if (Boolean.TRUE.equals(resourceMap.get(node).getIsValidLeaf())) { + hierarchies.add(new ArrayList<String>(workingPath)); + } + } + } + } + } + } + + return convertHierarchies(hierarchies, resourceMap); + } Set<List<RangerResourceDef>> convertHierarchies(Set<List<String>> hierarchies, Map<String, RangerResourceDef> resourceMap) { Set<List<RangerResourceDef>> result = new HashSet<List<RangerResourceDef>>(hierarchies.size()); @@ -408,7 +470,7 @@ public class RangerServiceDefHelper { /** * Converts resource list to resource map for efficient querying * - * @param resourceList + * @param resourceList - is guaranteed to be non-null and non-empty * @return */ Map<String, RangerResourceDef> getResourcesAsMap(List<RangerResourceDef> resourceList) { http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java index 5bb7c75..2566a4b 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java @@ -20,6 +20,7 @@ package org.apache.ranger.plugin.policyresourcematcher; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -30,6 +31,7 @@ import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; @@ -40,649 +42,657 @@ import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; import org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher; import org.apache.ranger.plugin.resourcematcher.RangerResourceMatcher; -import com.google.common.collect.Sets; - public class RangerDefaultPolicyResourceMatcher implements RangerPolicyResourceMatcher { - private static final Log LOG = LogFactory.getLog(RangerDefaultPolicyResourceMatcher.class); - - protected RangerServiceDef serviceDef; - protected RangerPolicy policy; - protected Map<String, RangerPolicyResource> policyResources; - - private Map<String, RangerResourceMatcher> matchers; - private boolean needsDynamicEval; - private List<RangerResourceDef> firstValidResourceDefHierarchy; - /* - * For hive resource policy: - * lastNonAnyMatcherIndex will be set to - * 0 : if all matchers in policy are '*'; such as database=*, table=*, column=* - * 1 : database=hr, table=*, column=* - * 2 : database=<any>, table=employee, column=* - * 3 : database=<any>, table=<any>, column=ssn - */ - private int lastNonAnyMatcherIndex; - - @Override - public void setServiceDef(RangerServiceDef serviceDef) { - this.serviceDef = serviceDef; - } - - @Override - public void setPolicy(RangerPolicy policy) { - this.policy = policy; - - setPolicyResources(policy == null ? null : policy.getResources()); - } - - @Override - public void setPolicyResources(Map<String, RangerPolicyResource> policyResources) { - this.policyResources = policyResources; - } - - @Override - public boolean getNeedsDynamicEval() { - return needsDynamicEval; - } - - @Override - public void init() { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.init()"); - } - - String errorText = ""; - - if(policyResources != null && !policyResources.isEmpty() && serviceDef != null) { - Set<String> policyResourceKeySet = policyResources.keySet(); - - RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef, false); - int policyType = policy != null && policy.getPolicyType() != null ? policy.getPolicyType() : RangerPolicy.POLICY_TYPE_ACCESS; - Set<List<RangerResourceDef>> validResourceHierarchies = serviceDefHelper.getResourceHierarchies(policyType); - - for (List<RangerResourceDef> validResourceHierarchy : validResourceHierarchies) { - - Set<String> resourceDefNameSet = serviceDefHelper.getAllResourceNames(validResourceHierarchy); - - if ((Sets.difference(policyResourceKeySet, resourceDefNameSet)).isEmpty()) { - - firstValidResourceDefHierarchy = validResourceHierarchy; - break; - - } - - } - - if (firstValidResourceDefHierarchy != null) { - List<String> resourceDefNameOrderedList = serviceDefHelper.getAllResourceNamesOrdered(firstValidResourceDefHierarchy); - - boolean foundGapsInResourceSpecs = false; - boolean skipped = false; - - for (String resourceDefName : resourceDefNameOrderedList) { - RangerPolicyResource policyResource = policyResources.get(resourceDefName); - if (policyResource == null) { - skipped = true; - } else if (skipped) { - foundGapsInResourceSpecs = true; - break; - } - } - - if (foundGapsInResourceSpecs) { - - errorText = "policyResources does not specify contiguous sequence in any valid resourcedef hiearchy."; - if (LOG.isDebugEnabled()) { - LOG.debug("RangerDefaultPolicyResourceMatcher.init() failed: Gaps found in policyResources, internal error, skipping.."); - } - firstValidResourceDefHierarchy = null; - - } else { - matchers = new HashMap<>(); - - for (RangerResourceDef resourceDef : firstValidResourceDefHierarchy) { - - String resourceName = resourceDef.getName(); - RangerPolicyResource policyResource = policyResources.get(resourceName); - - if (policyResource != null) { - RangerResourceMatcher matcher = createResourceMatcher(resourceDef, policyResource); - - if (matcher != null) { - if (!needsDynamicEval && matcher.getNeedsDynamicEval()) { - needsDynamicEval = true; - } - matchers.put(resourceName, matcher); - if (!matcher.isMatchAny()) { - lastNonAnyMatcherIndex = matchers.size(); - } - } else { - LOG.error("failed to find matcher for resource " + resourceName); - } - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("RangerDefaultPolicyResourceMatcher.init() - no matcher created for " + resourceName + ". Continuing ..."); - } - } - } - } - } else { - errorText = "policyResources elements are not part of any valid resourcedef hierarchy."; - } - } else { - errorText = " policyResources is null or empty, or serviceDef is null."; - } - - if(matchers == null) { - Set<String> policyResourceKeys = policyResources == null ? null : policyResources.keySet(); - StringBuilder sb = new StringBuilder(); - if (CollectionUtils.isNotEmpty(policyResourceKeys)) { - for (String policyResourceKeyName : policyResourceKeys) { - sb.append(" ").append(policyResourceKeyName).append(" "); - } - } - String keysString = sb.toString(); - String serviceDefName = serviceDef == null ? "" : serviceDef.getName(); - String validHierarchy = ""; - if (serviceDef != null && CollectionUtils.isNotEmpty(firstValidResourceDefHierarchy)) { - RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef, false); - List<String> resourceDefNameOrderedList = serviceDefHelper.getAllResourceNamesOrdered(firstValidResourceDefHierarchy); - - for (String resourceDefName : resourceDefNameOrderedList) { - validHierarchy += " " + resourceDefName + " "; - } - } - LOG.warn("RangerDefaultPolicyResourceMatcher.init() failed: " + errorText + " (serviceDef=" + serviceDefName + ", policyResourceKeys=" + keysString - + ", validHierarchy=" + validHierarchy + ")"); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.init()"); - } - } - - @Override - public RangerServiceDef getServiceDef() { - return serviceDef; - } - - @Override - public RangerResourceMatcher getResourceMatcher(String resourceName) { - return matchers != null ? matchers.get(resourceName) : null; - } - - @Override - public boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.isMatch(" + resources + ", " + evalContext + ")"); - } - - boolean ret = false; - - if(serviceDef != null && serviceDef.getResources() != null) { - Collection<String> resourceKeys = resources == null ? null : resources.keySet(); - Collection<String> policyKeys = matchers == null ? null : matchers.keySet(); - - boolean keysMatch = CollectionUtils.isEmpty(resourceKeys) || (policyKeys != null && policyKeys.containsAll(resourceKeys)); - - if(keysMatch) { - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - String resourceName = resourceDef.getName(); - RangerPolicyResource resourceValues = resources == null ? null : resources.get(resourceName); - RangerResourceMatcher matcher = matchers == null ? null : matchers.get(resourceName); - - // when no value exists for a resourceName, consider it a match only if: policy doesn't have a matcher OR matcher allows no-value resource - if(resourceValues == null || CollectionUtils.isEmpty(resourceValues.getValues())) { - ret = matcher == null || matcher.isMatch(null, null); - } else if(matcher != null) { - for(String resourceValue : resourceValues.getValues()) { - ret = matcher.isMatch(resourceValue, evalContext); - - if(! ret) { - break; - } - } - } - - if(! ret) { - break; - } - } - } else { - if(LOG.isDebugEnabled()) { - LOG.debug("isMatch(): keysMatch=false. resourceKeys=" + resourceKeys + "; policyKeys=" + policyKeys); - } - } - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.isMatch(" + resources + ", " + evalContext + "): " + ret); - } - - return ret; - } - - @Override - public boolean isCompleteMatch(RangerAccessResource resource, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resource + ", " + evalContext + ")"); - } - - boolean ret = false; - - if(serviceDef != null && serviceDef.getResources() != null) { - Collection<String> resourceKeys = resource == null ? null : resource.getKeys(); - Collection<String> policyKeys = matchers == null ? null : matchers.keySet(); - - boolean keysMatch = resourceKeys != null && policyKeys != null && CollectionUtils.isEqualCollection(resourceKeys, policyKeys); - - if(keysMatch) { - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - String resourceName = resourceDef.getName(); - String resourceValue = resource == null ? null : resource.getValue(resourceName); - RangerResourceMatcher matcher = matchers == null ? null : matchers.get(resourceName); - - if(StringUtils.isEmpty(resourceValue)) { - ret = matcher == null || matcher.isCompleteMatch(resourceValue, evalContext); - } else { - ret = matcher != null && matcher.isCompleteMatch(resourceValue, evalContext); - } - - if(! ret) { - break; - } - } - } else { - if(LOG.isDebugEnabled()) { - LOG.debug("isCompleteMatch(): keysMatch=false. resourceKeys=" + resourceKeys + "; policyKeys=" + policyKeys); - } - } - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resource + ", " + evalContext + "): " + ret); - } - - return ret; - } - - @Override - public boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resources + ", " + evalContext + ")"); - } - - boolean ret = false; - - if(serviceDef != null && serviceDef.getResources() != null) { - Collection<String> resourceKeys = resources == null ? null : resources.keySet(); - Collection<String> policyKeys = matchers == null ? null : matchers.keySet(); - - boolean keysMatch = resourceKeys != null && policyKeys != null && CollectionUtils.isEqualCollection(resourceKeys, policyKeys); - - if(keysMatch) { - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - String resourceName = resourceDef.getName(); - RangerPolicyResource resourceValues = resources == null ? null : resources.get(resourceName); - RangerPolicyResource policyValues = policyResources == null ? null : policyResources.get(resourceName); - - if(resourceValues == null || CollectionUtils.isEmpty(resourceValues.getValues())) { - ret = (policyValues == null || CollectionUtils.isEmpty(policyValues.getValues())); - } else if(policyValues != null && CollectionUtils.isNotEmpty(policyValues.getValues())) { - ret = CollectionUtils.isEqualCollection(resourceValues.getValues(), policyValues.getValues()); - } - - if(! ret) { - break; - } - } - } else { - if(LOG.isDebugEnabled()) { - LOG.debug("isCompleteMatch(): keysMatch=false. resourceKeys=" + resourceKeys + "; policyKeys=" + policyKeys); - } - } - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resources + ", " + evalContext + "): " + ret); - } - - return ret; - } - - @Override - public boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext) { - return isMatch(resource, MatchScope.SELF_OR_ANCESTOR, evalContext); - } - - @Override - public boolean isMatch(RangerPolicy policy, MatchScope scope, Map<String, Object> evalContext) { - - boolean ret = false; - MatchType matchType = MatchType.NONE; - - Map<String, RangerPolicyResource> resources = policy.getResources(); - - if (MapUtils.isNotEmpty(resources)) { - - RangerAccessResourceImpl accessResource = new RangerAccessResourceImpl(); - accessResource.setServiceDef(serviceDef); - - // Build up accessResource resourceDef by resourceDef. - // For each resourceDef, - // examine policy-values one by one. - // The first value that is acceptable, that is, - // value matches in any way, is used for that resourceDef, and - // next resourceDef is processed. - // If none of the values matches, the policy as a whole definitely will not match, - // therefore, the match is failed - // After all resourceDefs are processed, and some match is achieved at every - // level, the final matchType (which is for the entire policy) is checked against - // requested scope to determine the match-result. - - // Unit tests in TestDefaultPolicyResourceForPolicy.java, test_defaultpolicyresourcematcher_for_policy.json, - // and test_defaultpolicyresourcematcher_for_hdfs_policy.json - - for (RangerResourceDef resourceDef : firstValidResourceDefHierarchy) { - - ret = false; - matchType = MatchType.NONE; - - String name = resourceDef.getName(); - RangerPolicyResource policyResource = resources.get(name); - - if (policyResource != null) { - for (String value : policyResource.getValues()) { - - accessResource.setValue(name, value); - - matchType = getMatchType(accessResource, evalContext); - - if (matchType != MatchType.NONE) { // One value for this resourceDef matched - ret = true; - break; - } - } - } - - if (!ret) { // None of the values specified for this resourceDef matched, no point in continuing with next resourceDef - break; - } - } - ret = ret && isMatch(scope, matchType); - } - return ret; - } - - @Override - public boolean isMatch(RangerAccessResource resource, MatchScope scope, Map<String, Object> evalContext) { - - final boolean ret; - - MatchType matchType = getMatchType(resource, evalContext); - ret = isMatch(scope, matchType); - - return ret; - } - - @Override - public MatchType getMatchType(RangerAccessResource resource, Map<String, Object> evalContext) { - if (LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.getMatchType(" + resource + evalContext + ")"); - } - - int matchersSize = matchers == null ? 0 : matchers.size(); - int resourceKeysSize = resource == null || resource.getKeys() == null ? 0 : resource.getKeys().size(); - - MatchType ret = MatchType.NONE; - - if (!isValid(resource)) { - ret = MatchType.NONE; - } else if (matchersSize == 0 || lastNonAnyMatcherIndex == 0) { - ret = resourceKeysSize == 0 ? MatchType.SELF : MatchType.ANCESTOR; - } else if (resourceKeysSize == 0) { - ret = MatchType.DESCENDANT; - } else { - int index = 0; - for (RangerResourceDef resourceDef : firstValidResourceDefHierarchy) { - - String resourceName = resourceDef.getName(); - RangerResourceMatcher matcher = matchers.get(resourceName); - String resourceValue = resource.getValue(resourceName); - - if (resourceValue != null) { - if (matcher != null) { - index++; - if (matcher.isMatch(resourceValue, evalContext)) { - ret = index == resourceKeysSize && matcher.isMatchAny() ? MatchType.ANCESTOR : MatchType.SELF; - } else { - ret = MatchType.NONE; - break; - } - } else { - // More resource-levels than matchers - ret = MatchType.ANCESTOR; - break; - } - } else { - if (matcher != null) { - // More matchers than resource-levels - if (index >= lastNonAnyMatcherIndex) { - // All AnyMatch matchers after this - ret = MatchType.ANCESTOR; - } else { - ret = MatchType.DESCENDANT; - } - } else { - // Common part of several possible hierarchies matched - if (resourceKeysSize > index) { - ret = MatchType.ANCESTOR; - } - } - break; - } - } - - } - - if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.getMatchType(" + resource + evalContext + "): " + ret); - } - - return ret; - } - - private boolean isValidResourceDefHierachyForResource(List<RangerResourceDef> resourceHierarchy, RangerAccessResource resource) { - boolean foundAllResourceKeys = true; - - for (String resourceKey : resource.getKeys()) { - boolean found = false; - for (RangerResourceDef resourceDef : resourceHierarchy) { - if (resourceDef.getName().equals(resourceKey)) { - found = true; - break; - } - } - if (!found) { - foundAllResourceKeys = false; - break; - } - } - - return foundAllResourceKeys; - } - - private boolean isValid(RangerAccessResource resource) { - if (LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.isValid(" + resource + ")"); - } - - boolean ret = true; - - if (matchers != null && resource != null && resource.getKeys() != null) { - if (matchers.keySet().containsAll(resource.getKeys()) || resource.getKeys().containsAll(matchers.keySet())) { - - List<RangerResourceDef> aValidHierarchy = null; - - if (resource.getKeys().containsAll(matchers.keySet()) && resource.getKeys().size() > matchers.keySet().size()) { - if (isValidResourceDefHierachyForResource(firstValidResourceDefHierarchy, resource)) { - aValidHierarchy = firstValidResourceDefHierarchy; - } else { - RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef, false); - int policyType = policy != null && policy.getPolicyType() != null ? policy.getPolicyType() : RangerPolicy.POLICY_TYPE_ACCESS; - Set<List<RangerResourceDef>> validResourceHierarchies = serviceDefHelper.getResourceHierarchies(policyType); - - for (List<RangerResourceDef> resourceHierarchy : validResourceHierarchies) { - if (resourceHierarchy == firstValidResourceDefHierarchy) { // Pointer comparison - // firstValidResourceDefHierarchy is already checked before and it does not match - continue; - } - - if (isValidResourceDefHierachyForResource(resourceHierarchy, resource)) { - aValidHierarchy = resourceHierarchy; - break; - } - } - } - } else { - aValidHierarchy = firstValidResourceDefHierarchy; - } - - if (aValidHierarchy != null) { - boolean skipped = false; - - for (RangerResourceDef resourceDef : aValidHierarchy) { - - String resourceName = resourceDef.getName(); - String resourceValue = resource.getValue(resourceName); - - if (resourceValue == null) { - if (!skipped) { - skipped = true; - } - } else { - if (skipped) { - ret = false; - break; - } - } - - } - } else { - ret = false; - } - } else { - ret = false; - } - } - - if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.isValid(" + resource + "): " + ret); - } - - return ret; - } - - private boolean isMatch(final MatchScope scope, final MatchType matchType) { - final boolean ret; - switch (scope) { - case SELF_OR_ANCESTOR_OR_DESCENDANT: { - ret = matchType != MatchType.NONE; - break; - } - case SELF: { - ret = matchType == MatchType.SELF; - break; - } - case SELF_OR_DESCENDANT: { - ret = matchType == MatchType.SELF || matchType == MatchType.DESCENDANT; - break; - } - case SELF_OR_ANCESTOR: { - ret = matchType == MatchType.SELF || matchType == MatchType.ANCESTOR; - break; - } - case DESCENDANT: { - ret = matchType == MatchType.DESCENDANT; - break; - } - case ANCESTOR: { - ret = matchType == MatchType.ANCESTOR; - break; - } - default: - ret = matchType != MatchType.NONE; - break; - } - return ret; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - toString(sb); - - return sb.toString(); - } - - @Override - public StringBuilder toString(StringBuilder sb) { - sb.append("RangerDefaultPolicyResourceMatcher={"); - - sb.append("matchers={"); - if(matchers != null) { - for(RangerResourceMatcher matcher : matchers.values()) { - sb.append("{").append(matcher).append("} "); - } - } - sb.append("} "); - - sb.append("}"); - - return sb; - } - - protected static RangerResourceMatcher createResourceMatcher(RangerResourceDef resourceDef, RangerPolicyResource resource) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyResourceMatcher.createResourceMatcher(" + resourceDef + ", " + resource + ")"); - } - - RangerResourceMatcher ret = null; - - if (resourceDef != null) { - String resName = resourceDef.getName(); - String clsName = resourceDef.getMatcher(); - - if (!StringUtils.isEmpty(clsName)) { - try { - @SuppressWarnings("unchecked") - Class<RangerResourceMatcher> matcherClass = (Class<RangerResourceMatcher>) Class.forName(clsName); - - ret = matcherClass.newInstance(); - } catch (Exception excp) { - LOG.error("failed to instantiate resource matcher '" + clsName + "' for '" + resName + "'. Default resource matcher will be used", excp); - } - } - - - if (ret == null) { - ret = new RangerDefaultResourceMatcher(); - } - - if (ret != null) { - ret.setResourceDef(resourceDef); - ret.setPolicyResource(resource); - ret.init(); - } - } else { - LOG.error("RangerDefaultPolicyResourceMatcher: RangerResourceDef is null"); - } - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyResourceMatcher.createResourceMatcher(" + resourceDef + ", " + resource + "): " + ret); - } - - return ret; - } + private static final Log LOG = LogFactory.getLog(RangerDefaultPolicyResourceMatcher.class); + + protected RangerServiceDef serviceDef; + protected RangerPolicy policy; + protected Map<String, RangerPolicyResource> policyResources; + + private Map<String, RangerResourceMatcher> allMatchers; + private boolean needsDynamicEval = false; + private List<RangerResourceDef> validResourceHierarchy; + private boolean isInitialized = false; + private RangerServiceDefHelper serviceDefHelper; + + @Override + public void setServiceDef(RangerServiceDef serviceDef) { + if (isInitialized) { + LOG.warn("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + "): already initialized. init() must be done again after updating serviceDef"); + } + + this.serviceDef = serviceDef; + } + + @Override + public void setPolicy(RangerPolicy policy) { + if (isInitialized) { + LOG.warn("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + "): already initialized. init() must be done again after updating policy"); + } + + this.policy = policy; + this.policyResources = (policy == null ? null : policy.getResources()); + } + + @Override + public void setPolicyResources(Map<String, RangerPolicyResource> policyResources) { + if (isInitialized) { + LOG.warn("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + "): already initialized. init() must be done again after updating policy-resources"); + } + + this.policyResources = policyResources; + } + + @Override + public boolean getNeedsDynamicEval() { return needsDynamicEval; } + + @Override + public void init() { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init()"); + } + + allMatchers = null; + needsDynamicEval = false; + validResourceHierarchy = null; + isInitialized = false; + serviceDefHelper = null; + + String errorText = ""; + + boolean useCache = RangerConfiguration.getInstance().getBoolean("ranger.plugin.use-cache-for-service-def-helper", false); + + if (policyResources != null && !policyResources.isEmpty() && serviceDef != null) { + serviceDefHelper = new RangerServiceDefHelper(serviceDef, useCache); + + Set<List<RangerResourceDef>> resourceHierarchies = serviceDefHelper.getResourceHierarchies(getPolicyType(), policyResources.keySet()); + int validHierarchiesCount = 0; + + for (List<RangerResourceDef> resourceHierarchy : resourceHierarchies) { + boolean foundGapsInResourceSpecs = false; + boolean skipped = false; + + for (RangerResourceDef resourceDef : resourceHierarchy) { + RangerPolicyResource policyResource = policyResources.get(resourceDef.getName()); + + if (policyResource == null) { + skipped = true; + } else if (skipped) { + foundGapsInResourceSpecs = true; + break; + } + } + + if (foundGapsInResourceSpecs) { + LOG.warn("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init(): gaps found in policyResources, skipping hierarchy:[" + resourceHierarchies + "]"); + } else { + validHierarchiesCount++; + + if (validHierarchiesCount == 1) { + validResourceHierarchy = resourceHierarchy; + } else { + validResourceHierarchy = null; + } + } + } + + if (validHierarchiesCount > 0) { + allMatchers = new HashMap<>(); + + for (List<RangerResourceDef> resourceHierarchy : resourceHierarchies) { + for (RangerResourceDef resourceDef : resourceHierarchy) { + String resourceName = resourceDef.getName(); + + if (allMatchers.get(resourceName) != null) { + continue; + } + + RangerPolicyResource policyResource = policyResources.get(resourceName); + + if (policyResource == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init(): no matcher created for " + resourceName + ". Continuing ..."); + } + + continue; + } + + RangerResourceMatcher matcher = createResourceMatcher(resourceDef, policyResource); + + if (matcher != null) { + if (!needsDynamicEval && matcher.getNeedsDynamicEval()) { + needsDynamicEval = true; + } + + allMatchers.put(resourceName, matcher); + } else { + LOG.error("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init(): failed to find matcher for resource " + resourceName); + + allMatchers = null; + errorText = "no matcher found for resource " + resourceName; + + break; + } + } + + if (allMatchers == null) { + break; + } + } + } else { + errorText = "policyResources elements are not part of any valid resourcedef hierarchy."; + } + } else { + errorText = "policyResources is null or empty, or serviceDef is null."; + } + + if (allMatchers == null) { + serviceDefHelper = null; + validResourceHierarchy = null; + + Set<String> policyResourceKeys = policyResources == null ? null : policyResources.keySet(); + String serviceDefName = serviceDef == null ? "" : serviceDef.getName(); + StringBuilder keysString = new StringBuilder(); + + if (CollectionUtils.isNotEmpty(policyResourceKeys)) { + for (String policyResourceKeyName : policyResourceKeys) { + keysString.append(policyResourceKeyName).append(" "); + } + } + + LOG.error("RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init() failed: " + errorText + " (serviceDef=" + serviceDefName + ", policyResourceKeys=" + keysString.toString()); + } else { + isInitialized = true; + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher(policyId=" + getPolicyId() + ").init(): ret=" + isInitialized); + } + } + + @Override + public RangerServiceDef getServiceDef() { + return serviceDef; + } + + @Override + public RangerResourceMatcher getResourceMatcher(String resourceName) { + return allMatchers != null ? allMatchers.get(resourceName) : null; + } + + @Override + public boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.isMatch(" + resources + ", " + evalContext + ")"); + } + + boolean ret = isMatch(resources, MatchScope.SELF_OR_ANCESTOR, true, evalContext); + + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.isMatch(" + resources + ", " + evalContext + "): " + ret); + } + + return ret; + } + + @Override + public boolean isCompleteMatch(RangerAccessResource resource, Map<String, Object> evalContext) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resource + ", " + evalContext + ")"); + } + + boolean ret = false; + Collection<String> resourceKeys = resource == null ? null : resource.getKeys(); + Collection<String> policyKeys = policyResources == null ? null : policyResources.keySet(); + boolean keysMatch = resourceKeys != null && policyKeys != null && CollectionUtils.isEqualCollection(resourceKeys, policyKeys); + + if (keysMatch) { + for (RangerResourceDef resourceDef : serviceDef.getResources()) { + String resourceName = resourceDef.getName(); + String resourceValue = resource == null ? null : resource.getValue(resourceName); + RangerResourceMatcher matcher = allMatchers == null ? null : allMatchers.get(resourceName); + + if (StringUtils.isEmpty(resourceValue)) { + ret = matcher == null || matcher.isCompleteMatch(resourceValue, evalContext); + } else { + ret = matcher != null && matcher.isCompleteMatch(resourceValue, evalContext); + } + + if (!ret) { + break; + } + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("isCompleteMatch(): keysMatch=false. resourceKeys=" + resourceKeys + "; policyKeys=" + policyKeys); + } + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resource + ", " + evalContext + "): " + ret); + } + + return ret; + } + + @Override + public boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resources + ", " + evalContext + ")"); + } + + boolean ret = false; + Collection<String> resourceKeys = resources == null ? null : resources.keySet(); + Collection<String> policyKeys = policyResources == null ? null : policyResources.keySet(); + boolean keysMatch = resourceKeys != null && policyKeys != null && CollectionUtils.isEqualCollection(resourceKeys, policyKeys); + + if (keysMatch) { + for (RangerResourceDef resourceDef : serviceDef.getResources()) { + String resourceName = resourceDef.getName(); + RangerPolicyResource resourceValues = resources == null ? null : resources.get(resourceName); + RangerPolicyResource policyValues = policyResources == null ? null : policyResources.get(resourceName); + + if (resourceValues == null || CollectionUtils.isEmpty(resourceValues.getValues())) { + ret = (policyValues == null || CollectionUtils.isEmpty(policyValues.getValues())); + } else if (policyValues != null && CollectionUtils.isNotEmpty(policyValues.getValues())) { + ret = CollectionUtils.isEqualCollection(resourceValues.getValues(), policyValues.getValues()); + } + + if (!ret) { + break; + } + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("isCompleteMatch(): keysMatch=false. resourceKeys=" + resourceKeys + "; policyKeys=" + policyKeys); + } + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.isCompleteMatch(" + resources + ", " + evalContext + "): " + ret); + } + + return ret; + } + + @Override + public boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext) { + return isMatch(resource, MatchScope.SELF_OR_ANCESTOR, evalContext); + } + + @Override + public boolean isMatch(RangerPolicy policy, MatchScope scope, Map<String, Object> evalContext) { + return isMatch(policy.getResources(), scope, false, evalContext); + } + + private int getPolicyType() { + return policy != null && policy.getPolicyType() != null ? policy.getPolicyType() : RangerPolicy.POLICY_TYPE_ACCESS; + } + + private Long getPolicyId() { + return policy != null ? policy.getId() : null; + } + + boolean isMatch(Map<String, RangerPolicyResource> resources, MatchScope scope, boolean mustMatchAllPolicyValues, Map<String, Object> evalContext) { + boolean ret = false; + + if (MapUtils.isNotEmpty(resources)) { + List<RangerResourceDef> hierarchy = getMatchingHierarchy(resources.keySet()); + + if (CollectionUtils.isNotEmpty(hierarchy)) { + MatchType matchType = MatchType.NONE; + RangerAccessResourceImpl accessResource = new RangerAccessResourceImpl(); + + accessResource.setServiceDef(serviceDef); + + // Build up accessResource resourceDef by resourceDef. + // For each resourceDef, + // examine policy-values one by one. + // The first value that is acceptable, that is, + // value matches in any way, is used for that resourceDef, and + // next resourceDef is processed. + // If none of the values matches, the policy as a whole definitely will not match, + // therefore, the match is failed + // After all resourceDefs are processed, and some match is achieved at every + // level, the final matchType (which is for the entire policy) is checked against + // requested scope to determine the match-result. + + // Unit tests in TestDefaultPolicyResourceForPolicy.java, test_defaultpolicyresourcematcher_for_policy.json, + // test_defaultpolicyresourcematcher_for_hdfs_policy.json, and + // test_defaultpolicyresourcematcher_for_resource_specific_policy.json + + boolean skipped = false; + + for (RangerResourceDef resourceDef : hierarchy) { + String name = resourceDef.getName(); + RangerPolicyResource policyResource = resources.get(name); + + if (policyResource != null && CollectionUtils.isNotEmpty(policyResource.getValues())) { + ret = false; + matchType = MatchType.NONE; + + if (!skipped) { + for (String value : policyResource.getValues()) { + accessResource.setValue(name, value); + + matchType = getMatchType(accessResource, evalContext); + + if (matchType != MatchType.NONE) { // One value for this resourceDef matched + ret = true; + + if (!mustMatchAllPolicyValues) { + break; + } + } + } + } else { + break; + } + } else { + skipped = true; + } + + if (!ret) { // None of the values specified for this resourceDef matched, no point in continuing with next resourceDef + break; + } + } + ret = ret && isMatch(scope, matchType); + } + } + + return ret; + } + + @Override + public boolean isMatch(RangerAccessResource resource, MatchScope scope, Map<String, Object> evalContext) { + MatchType matchType = getMatchType(resource, evalContext); + boolean ret = isMatch(scope, matchType); + + return ret; + } + + @Override + public MatchType getMatchType(RangerAccessResource resource, Map<String, Object> evalContext) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.getMatchType(" + resource + evalContext + ")"); + } + + MatchType ret = MatchType.NONE; + int policyKeysSize = policyResources == null ? 0 : policyResources.size(); + int resourceKeysSize = resource == null || resource.getKeys() == null ? 0 : resource.getKeys().size(); + + if (policyKeysSize == 0 && resourceKeysSize == 0) { + ret = MatchType.SELF; + } else { + List<RangerResourceDef> hierarchy = getMatchingHierarchy(resource); + if (CollectionUtils.isNotEmpty(hierarchy)) { + int lastNonAnyMatcherIndex = 0; + /* + * For hive resource policy: + * lastNonAnyMatcherIndex will be set to + * 0 : if all matchers in policy are '*'; such as database=*, table=*, column=* + * 1 : database=hr, table=*, column=* + * 2 : database=<any>, table=employee, column=* + * 3 : database=<any>, table=<any>, column=ssn + */ + int matchersSize = 0; + + for (RangerResourceDef resourceDef : hierarchy) { + RangerResourceMatcher matcher = allMatchers.get(resourceDef.getName()); + if (matcher != null) { + matchersSize++; + if (!matcher.isMatchAny()) { + lastNonAnyMatcherIndex = matchersSize; + } + } + } + + if (resourceKeysSize == 0 && lastNonAnyMatcherIndex == 0) { + ret = MatchType.SELF; + } else if (lastNonAnyMatcherIndex == 0) { + ret = MatchType.ANCESTOR; + } else { + int index = 0; + for (RangerResourceDef resourceDef : hierarchy) { + + String resourceName = resourceDef.getName(); + RangerResourceMatcher matcher = allMatchers.get(resourceName); + String resourceValue = resource.getValue(resourceName); + + if (resourceValue != null) { + if (matcher != null) { + index++; + if (matcher.isMatch(resourceValue, evalContext)) { + ret = index == resourceKeysSize && matcher.isMatchAny() ? MatchType.ANCESTOR : MatchType.SELF; + } else { + ret = MatchType.NONE; + break; + } + } else { + // More resource-levels than matchers + ret = MatchType.ANCESTOR; + break; + } + } else { + if (matcher != null) { + // More matchers than resource-levels + if (index >= lastNonAnyMatcherIndex) { + // All AnyMatch matchers after this + ret = MatchType.ANCESTOR; + } else { + ret = MatchType.DESCENDANT; + } + } else { + // Common part of several possible hierarchies matched + if (resourceKeysSize > index) { + ret = MatchType.ANCESTOR; + } + } + break; + } + } + if (ret == MatchType.SELF && resourceKeysSize > matchersSize) { + ret = MatchType.ANCESTOR; + } + } + } + + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.getMatchType(" + resource + evalContext + "): " + ret); + } + + return ret; + } + + private List<RangerResourceDef> getMatchingHierarchy(Set<String> resourceKeys) { + List<RangerResourceDef> ret = null; + + if (CollectionUtils.isNotEmpty(resourceKeys)) { + Set<List<RangerResourceDef>> resourceHierarchies = serviceDefHelper == null ? Collections.EMPTY_SET : serviceDefHelper.getResourceHierarchies(getPolicyType(), resourceKeys); + + // pick the shortest hierarchy + for (List<RangerResourceDef> resourceHierarchy : resourceHierarchies) { + if (ret == null) { + ret = resourceHierarchy; + } else { + if (resourceHierarchy.size() < ret.size()) { + ret = resourceHierarchy; + if (ret.size() == resourceKeys.size()) { + break; + } + } + } + } + } + + return ret; + } + + private List<RangerResourceDef> getMatchingHierarchy(RangerAccessResource resource) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.getMatchingHierarchy(" + resource + ")"); + } + + final List<RangerResourceDef> ret; + + Set<String> policyResourcesKeySet = policyResources == null ? Collections.EMPTY_SET : policyResources.keySet(); + + if (resource != null && resource.getKeys() != null) { + List<RangerResourceDef> aValidHierarchy = null; + + if (validResourceHierarchy != null && serviceDefHelper != null) { + if (serviceDefHelper.hierarchyHasAllResources(validResourceHierarchy, resource.getKeys())) { + aValidHierarchy = validResourceHierarchy; + } + } else { + if (policyResourcesKeySet.containsAll(resource.getKeys())) { + aValidHierarchy = getMatchingHierarchy(policyResourcesKeySet); + } else if (resource.getKeys().containsAll(policyResourcesKeySet)) { + aValidHierarchy = getMatchingHierarchy(resource.getKeys()); + } + } + + if (aValidHierarchy != null) { + boolean isValid = true; + boolean skipped = false; + + for (RangerResourceDef resourceDef : aValidHierarchy) { + String resourceName = resourceDef.getName(); + String resourceValue = resource.getValue(resourceName); + + if (resourceValue == null) { + if (!skipped) { + skipped = true; + } + } else { + if (skipped) { + isValid = false; + break; + } + } + } + + if (!isValid) { + aValidHierarchy = null; + } + } + + ret = aValidHierarchy; + } else { + ret = getMatchingHierarchy(policyResourcesKeySet); + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.getMatchingHierarchy(" + resource + "): " + ret); + } + + return ret; + } + + private boolean isMatch(final MatchScope scope, final MatchType matchType) { + final boolean ret; + switch (scope) { + case SELF_OR_ANCESTOR_OR_DESCENDANT: { + ret = matchType != MatchType.NONE; + break; + } + case SELF: { + ret = matchType == MatchType.SELF; + break; + } + case SELF_OR_DESCENDANT: { + ret = matchType == MatchType.SELF || matchType == MatchType.DESCENDANT; + break; + } + case SELF_OR_ANCESTOR: { + ret = matchType == MatchType.SELF || matchType == MatchType.ANCESTOR; + break; + } + case DESCENDANT: { + ret = matchType == MatchType.DESCENDANT; + break; + } + case ANCESTOR: { + ret = matchType == MatchType.ANCESTOR; + break; + } + default: + ret = matchType != MatchType.NONE; + break; + } + return ret; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + toString(sb); + + return sb.toString(); + } + + @Override + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerDefaultPolicyResourceMatcher={"); + + sb.append("isInitialized=").append(isInitialized).append(", "); + + sb.append("matchers={"); + if(allMatchers != null) { + for(RangerResourceMatcher matcher : allMatchers.values()) { + sb.append("{").append(matcher).append("} "); + } + } + sb.append("} "); + + sb.append("}"); + + return sb; + } + + protected static RangerResourceMatcher createResourceMatcher(RangerResourceDef resourceDef, RangerPolicyResource resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyResourceMatcher.createResourceMatcher(" + resourceDef + ", " + resource + ")"); + } + + RangerResourceMatcher ret = null; + + if (resourceDef != null) { + String resName = resourceDef.getName(); + String clsName = resourceDef.getMatcher(); + + if (!StringUtils.isEmpty(clsName)) { + try { + @SuppressWarnings("unchecked") + Class<RangerResourceMatcher> matcherClass = (Class<RangerResourceMatcher>) Class.forName(clsName); + + ret = matcherClass.newInstance(); + } catch (Exception excp) { + LOG.error("failed to instantiate resource matcher '" + clsName + "' for '" + resName + "'. Default resource matcher will be used", excp); + } + } + + + if (ret == null) { + ret = new RangerDefaultResourceMatcher(); + } + + ret.setResourceDef(resourceDef); + ret.setPolicyResource(resource); + ret.init(); + } else { + LOG.error("RangerDefaultPolicyResourceMatcher: RangerResourceDef is null"); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyResourceMatcher.createResourceMatcher(" + resourceDef + ", " + resource + "): " + ret); + } + + return ret; + } } http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java index f1c6b9f..25f9985 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java @@ -25,6 +25,7 @@ import java.util.Arrays; 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; @@ -38,6 +39,7 @@ import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; import org.apache.ranger.plugin.resourcematcher.RangerAbstractResourceMatcher; +import org.apache.ranger.plugin.util.ServiceDefUtil; public abstract class RangerBaseService { @@ -133,18 +135,6 @@ public abstract class RangerBaseService { return ret; } - public List<RangerPolicy.RangerPolicyItemAccess> getAndAllowAllAccesses() { - List<RangerPolicy.RangerPolicyItemAccess> ret = new ArrayList<RangerPolicy.RangerPolicyItemAccess>(); - - for (RangerServiceDef.RangerAccessTypeDef accessTypeDef : serviceDef.getAccessTypes()) { - RangerPolicy.RangerPolicyItemAccess access = new RangerPolicy.RangerPolicyItemAccess(); - access.setType(accessTypeDef.getName()); - access.setIsAllowed(true); - ret.add(access); - } - return ret; - } - private RangerPolicy getDefaultPolicy(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) throws Exception { if (LOG.isDebugEnabled()) { @@ -165,7 +155,7 @@ public abstract class RangerBaseService { List<RangerPolicy.RangerPolicyItem> policyItems = new ArrayList<RangerPolicy.RangerPolicyItem>(); //Create Default policy item for the service user - RangerPolicy.RangerPolicyItem policyItem = createDefaultPolicyItem(); + RangerPolicy.RangerPolicyItem policyItem = createDefaultPolicyItem(policy.getResources()); policyItems.add(policyItem); policy.setPolicyItems(policyItems); @@ -176,7 +166,7 @@ public abstract class RangerBaseService { return policy; } - private RangerPolicy.RangerPolicyItem createDefaultPolicyItem() throws Exception { + private RangerPolicy.RangerPolicyItem createDefaultPolicyItem(Map<String, RangerPolicy.RangerPolicyResource> policyResources) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("==> RangerBaseService.createDefaultPolicyItem()"); @@ -185,7 +175,10 @@ public abstract class RangerBaseService { RangerPolicy.RangerPolicyItem policyItem = new RangerPolicy.RangerPolicyItem(); policyItem.setUsers(getUserList()); - policyItem.setAccesses(getAndAllowAllAccesses()); + + List<RangerPolicy.RangerPolicyItemAccess> accesses = getAllowedAccesses(policyResources); + policyItem.setAccesses(accesses); + policyItem.setDelegateAdmin(true); if (LOG.isDebugEnabled()) { @@ -194,7 +187,29 @@ public abstract class RangerBaseService { return policyItem; } - private Map<String, RangerPolicy.RangerPolicyResource> createDefaultPolicyResource(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) throws Exception { + protected List<RangerPolicy.RangerPolicyItemAccess> getAllowedAccesses(Map<String, RangerPolicy.RangerPolicyResource> policyResources) { + List<RangerPolicy.RangerPolicyItemAccess> ret = new ArrayList<RangerPolicy.RangerPolicyItemAccess>(); + + RangerServiceDef.RangerResourceDef leafResourceDef = ServiceDefUtil.getLeafResourceDef(serviceDef, policyResources); + + if (leafResourceDef != null) { + Set<String> accessTypeRestrictions = leafResourceDef.getAccessTypeRestrictions(); + + for (RangerServiceDef.RangerAccessTypeDef accessTypeDef : serviceDef.getAccessTypes()) { + boolean isAccessTypeAllowed = CollectionUtils.isEmpty(accessTypeRestrictions) || accessTypeRestrictions.contains(accessTypeDef.getName());; + + if (isAccessTypeAllowed) { + RangerPolicy.RangerPolicyItemAccess access = new RangerPolicy.RangerPolicyItemAccess(); + access.setType(accessTypeDef.getName()); + access.setIsAllowed(true); + ret.add(access); + } + } + } + return ret; + } + + protected Map<String, RangerPolicy.RangerPolicyResource> createDefaultPolicyResource(List<RangerServiceDef.RangerResourceDef> resourceHierarchy) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("==> RangerBaseService.createDefaultPolicyResource()"); } http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultService.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultService.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultService.java new file mode 100644 index 0000000..c61ebd6 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultService.java @@ -0,0 +1,49 @@ +/* + * 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 java.util.List; +import java.util.Map; + +import org.apache.commons.collections.ListUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class RangerDefaultService extends RangerBaseService { + private static final Log LOG = LogFactory.getLog(RangerDefaultService.class); + + @Override + public Map<String, Object> validateConfig() throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("RangerDefaultService.validateConfig Service: (" + serviceName + " ), returning empty map"); + } + return MapUtils.EMPTY_MAP; + } + + @Override + public List<String> lookupResource(ResourceLookupContext context) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("RangerDefaultService.lookupResource Context: (" + context + "), returning empty list"); + } + return ListUtils.EMPTY_LIST; + } + +} http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java index 77808b8..f6c1e4d 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerResourceTrie.java @@ -46,7 +46,6 @@ public class RangerResourceTrie<T extends RangerPolicyResourceEvaluator> { private final boolean optWildcard; private final String wildcardChars; private final TrieNode root; - private final Comparator<T> comparator; public RangerResourceTrie(RangerServiceDef.RangerResourceDef resourceDef, List<T> evaluators) { this(resourceDef, evaluators, null); @@ -78,7 +77,6 @@ public class RangerResourceTrie<T extends RangerPolicyResourceEvaluator> { this.optWildcard = RangerAbstractResourceMatcher.getOptionWildCard(matcherOptions); this.wildcardChars = optWildcard ? DEFAULT_WILDCARD_CHARS + tokenReplaceSpecialChars : "" + tokenReplaceSpecialChars; this.root = new TrieNode(Character.valueOf((char)0)); - this.comparator = comparator; for(T evaluator : evaluators) { Map<String, RangerPolicyResource> policyResources = evaluator.getPolicyResource(); http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java index b0090d4..f8994a7 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java @@ -94,16 +94,30 @@ public class ServiceDefUtil { public static Integer getLeafResourceLevel(RangerServiceDef serviceDef, Map<String, RangerPolicy.RangerPolicyResource> policyResource) { Integer ret = null; + RangerResourceDef resourceDef = getLeafResourceDef(serviceDef, policyResource); + + if (resourceDef != null) { + ret = resourceDef.getLevel(); + } + + return ret; + } + + public static RangerResourceDef getLeafResourceDef(RangerServiceDef serviceDef, Map<String, RangerPolicy.RangerPolicyResource> policyResource) { + RangerResourceDef ret = null; + if(serviceDef != null && policyResource != null) { for(Map.Entry<String, RangerPolicy.RangerPolicyResource> entry : policyResource.entrySet()) { - String resource = entry.getKey(); - RangerResourceDef resourceDef = ServiceDefUtil.getResourceDef(serviceDef, resource); - - if(resourceDef != null && resourceDef.getLevel() != null) { - if(ret == null) { - ret = resourceDef.getLevel(); - } else if(ret < resourceDef.getLevel()) { - ret = resourceDef.getLevel(); + if (!isEmpty(entry.getValue())) { + String resource = entry.getKey(); + RangerResourceDef resourceDef = ServiceDefUtil.getResourceDef(serviceDef, resource); + + if (resourceDef != null && resourceDef.getLevel() != null) { + if (ret == null) { + ret = resourceDef; + } else if(ret.getLevel() < resourceDef.getLevel()) { + ret = resourceDef; + } } } } @@ -112,6 +126,22 @@ public class ServiceDefUtil { return ret; } + public static boolean isEmpty(RangerPolicy.RangerPolicyResource policyResource) { + boolean ret = true; + if (policyResource != null) { + List<String> resourceValues = policyResource.getValues(); + if (CollectionUtils.isNotEmpty(resourceValues)) { + for (String resourceValue : resourceValues) { + if (StringUtils.isNotBlank(resourceValue)) { + ret = false; + break; + } + } + } + } + return ret; + } + public static String getOption(Map<String, String> options, String name, String defaultValue) { String ret = options != null && name != null ? options.get(name) : null; @@ -276,6 +306,12 @@ public class ServiceDefUtil { if(StringUtils.isNotEmpty(delta.getRbKeyValidationMessage())) ret.setRbKeyValidationMessage(delta.getRbKeyValidationMessage()); + if(CollectionUtils.isNotEmpty(delta.getAccessTypeRestrictions())) + ret.setAccessTypeRestrictions(delta.getAccessTypeRestrictions()); + + if (delta.getIsValidLeaf() != null) + ret.setIsValidLeaf(delta.getIsValidLeaf()); + return ret; } http://git-wip-us.apache.org/repos/asf/ranger/blob/7985dd47/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java index 9bfa859..d8a1354 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java @@ -120,7 +120,7 @@ public class TestRangerPolicyValidator { { "col", false, true, false, "col\\d{1,2}", "tbl" }, // valid: col1, col47, etc.; invalid: col, col238, col1, etc., excludes == false, recursive == true { "udf", true, true, true, null, "db" } // same parent as tbl (simulating hive's multiple resource hierarchies) }; - + private final Object[][] policyResourceMap_good = new Object[][] { // resource-name, values, excludes, recursive { "db", new String[] { "db1", "db2" }, null, null }, @@ -804,17 +804,17 @@ public class TestRangerPolicyValidator { List<RangerResourceDef> resourceDefs = _utils.createResourceDefs(resourceDefData_multipleHierarchies); when(_serviceDef.getResources()).thenReturn(resourceDefs); // setup policy - Map<String, RangerPolicyResource> policyResources = _utils.createPolicyResourceMap(policyResourceMap_bad); + Map<String, RangerPolicyResource> policyResources = _utils.createPolicyResourceMap(policyResourceMap_bad); when(_policy.getResources()).thenReturn(policyResources); Assert.assertFalse("Missing required resource and unknown resource", _validator.isValidResourceNames(_policy, _failures, _serviceDef)); _utils.checkFailureForSemanticError(_failures, "policy resources"); - + // another bad resource map that straddles multiple hierarchies policyResources = _utils.createPolicyResourceMap(policyResourceMap_bad_multiple_hierarchies); when(_policy.getResources()).thenReturn(policyResources); _failures.clear(); Assert.assertFalse("Policy with resources for multiple hierarchies", _validator.isValidResourceNames(_policy, _failures, _serviceDef)); _utils.checkFailureForSemanticError(_failures, "policy resources", "incompatible"); - + // another bad policy resource map that could match multiple hierarchies but is short on mandatory resources for all of those matches policyResources = _utils.createPolicyResourceMap(policyResourceMap_bad_multiple_hierarchies_missing_mandatory); when(_policy.getResources()).thenReturn(policyResources);
