kumaab commented on code in PR #442: URL: https://github.com/apache/ranger/pull/442#discussion_r1881114027
########## agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResourceImpl.java: ########## @@ -19,250 +19,262 @@ package org.apache.ranger.plugin.policyengine; +import org.apache.commons.lang.ObjectUtils; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; + import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.lang.ObjectUtils; -import org.apache.ranger.plugin.model.RangerServiceDef; -import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; - public class RangerAccessResourceImpl implements RangerMutableResource { - private String ownerUser; - private Map<String, Object> elements; - private String stringifiedValue; - private String stringifiedCacheKeyValue; - private String leafName; - private RangerServiceDef serviceDef; - - public RangerAccessResourceImpl() { - this(null, null); - } - - public RangerAccessResourceImpl(Map<String, Object> elements) { - this(elements, null); - } - - public RangerAccessResourceImpl(Map<String, Object> elements, String ownerUser) { - this.elements = elements; - this.ownerUser = ownerUser; - } - - @Override - public String getOwnerUser() { - return ownerUser; - } - - @Override - public boolean exists(String name) { - return elements != null && elements.containsKey(name); - } - - @Override - public Object getValue(String name) { - Object ret = null; - - if(elements != null && elements.containsKey(name)) { - ret = elements.get(name); - } - - return ret; - } - - @Override - public Set<String> getKeys() { - Set<String> ret = null; - - if(elements != null) { - ret = elements.keySet(); - } - - return ret; - } - - @Override - public void setOwnerUser(String ownerUser) { - this.ownerUser = ownerUser; - } - - @Override - public void setValue(String name, Object value) { - if(value == null) { - if(elements != null) { - elements.remove(name); - - if(elements.isEmpty()) { - elements = null; - } - } - } else { - if(elements == null) { - elements = new HashMap<>(); - } - elements.put(name, value); - } - - // reset, so that these will be computed again with updated elements - stringifiedValue = stringifiedCacheKeyValue = leafName = null; - } - - @Override - public void setServiceDef(final RangerServiceDef serviceDef) { - this.serviceDef = serviceDef; - this.stringifiedValue = this.stringifiedCacheKeyValue = this.leafName = null; - } - - @Override - public RangerServiceDef getServiceDef() { - return this.serviceDef; - } - - @Override - public String getLeafName() { - String ret = leafName; - - if(ret == null) { - if(serviceDef != null && serviceDef.getResources() != null) { - List<RangerResourceDef> resourceDefs = serviceDef.getResources(); - - for(int idx = resourceDefs.size() - 1; idx >= 0; idx--) { - RangerResourceDef resourceDef = resourceDefs.get(idx); - - if(resourceDef != null && exists(resourceDef.getName())) { - ret = leafName = resourceDef.getName(); - break; + private String ownerUser; + private Map<String, Object> elements; + private String stringifiedValue; + private String stringifiedCacheKeyValue; + private String leafName; + private RangerServiceDef serviceDef; + + public RangerAccessResourceImpl() { + this(null, null); + } + + public RangerAccessResourceImpl(Map<String, Object> elements) { + this(elements, null); + } + + public RangerAccessResourceImpl(Map<String, Object> elements, String ownerUser) { + this.elements = elements; + this.ownerUser = ownerUser; + } + + @Override + public String getOwnerUser() { + return ownerUser; + } + + @Override + public boolean exists(String name) { + return elements != null && elements.containsKey(name); + } + + @Override + public Object getValue(String name) { + Object ret = null; + + if (elements != null && elements.containsKey(name)) { + ret = elements.get(name); + } + + return ret; + } + + @Override + public RangerServiceDef getServiceDef() { + return this.serviceDef; + } + + @Override + public Set<String> getKeys() { + Set<String> ret = null; + + if (elements != null) { + ret = elements.keySet(); + } + + return ret; + } + + @Override + public String getLeafName() { + String ret = leafName; + + if (ret == null) { + if (serviceDef != null && serviceDef.getResources() != null) { + List<RangerResourceDef> resourceDefs = serviceDef.getResources(); + + for (int idx = resourceDefs.size() - 1; idx >= 0; idx--) { + RangerResourceDef resourceDef = resourceDefs.get(idx); + + if (resourceDef != null && exists(resourceDef.getName())) { + ret = resourceDef.getName(); + leafName = ret; + + break; } - } - } - } - - return ret; - } - - @Override - public String getAsString() { - String ret = stringifiedValue; - - if(ret == null) { - if(serviceDef != null && serviceDef.getResources() != null) { - StringBuilder sb = new StringBuilder(); - - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - if(resourceDef == null || !exists(resourceDef.getName())) { - continue; - } - - if(sb.length() > 0) { - sb.append(RESOURCE_SEP); - } - - sb.append(getValue(resourceDef.getName())); - } - - if(sb.length() > 0) { - ret = stringifiedValue = sb.toString(); - } - } - } - - return ret; - } - - @Override - public String getCacheKey() { - String ret = stringifiedCacheKeyValue; + } + } + } - if(ret == null) { - if(serviceDef != null && serviceDef.getResources() != null) { - StringBuilder sb = new StringBuilder(); + return ret; + } - for(RangerResourceDef resourceDef : serviceDef.getResources()) { - if(resourceDef == null || !exists(resourceDef.getName())) { - continue; - } + @Override + public String getAsString() { + String ret = stringifiedValue; - if(sb.length() > 0) { - sb.append(RESOURCE_SEP); - } + if (ret == null) { + if (serviceDef != null && serviceDef.getResources() != null) { + StringBuilder sb = new StringBuilder(); - sb.append(resourceDef.getName()).append(RESOURCE_NAME_VAL_SEP).append(getValue(resourceDef.getName())); - } - - if(sb.length() > 0) { - ret = stringifiedCacheKeyValue = sb.toString(); - } - } - } - - return ret; - } - - @Override - public Map<String, Object> getAsMap() { - return elements == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(elements); - } - - @Override - public RangerAccessResource getReadOnlyCopy() { - return new RangerAccessResourceReadOnly(this); - } - - @Override - public boolean equals(Object obj) { - if(obj == null || !(obj instanceof RangerAccessResourceImpl)) { - return false; - } - - if(this == obj) { - return true; - } - - RangerAccessResourceImpl other = (RangerAccessResourceImpl) obj; - - return ObjectUtils.equals(ownerUser, other.ownerUser) && - ObjectUtils.equals(elements, other.elements); - } - - @Override - public int hashCode() { - int ret = 7; - - ret = 31 * ret + ObjectUtils.hashCode(ownerUser); - ret = 31 * ret + ObjectUtils.hashCode(elements); - - return ret; - } - - @Override - public String toString( ) { - StringBuilder sb = new StringBuilder(); + for (RangerResourceDef resourceDef : serviceDef.getResources()) { + if (resourceDef == null || !exists(resourceDef.getName())) { + continue; + } - toString(sb); + if (sb.length() > 0) { + sb.append(RESOURCE_SEP); + } - return sb.toString(); - } + sb.append(getValue(resourceDef.getName())); + } - public StringBuilder toString(StringBuilder sb) { - sb.append("RangerResourceImpl={"); + if (sb.length() > 0) { + ret = sb.toString(); + stringifiedValue = ret; + } + } + } - sb.append("ownerUser={").append(ownerUser).append("} "); + return ret; + } - sb.append("elements={"); - if(elements != null) { - for(Map.Entry<String, Object> e : elements.entrySet()) { - sb.append(e.getKey()).append("=").append(e.getValue()).append("; "); - } - } - sb.append("} "); + @Override + public String getCacheKey() { + String ret = stringifiedCacheKeyValue; - sb.append("}"); + if (ret == null) { + if (serviceDef != null && serviceDef.getResources() != null) { + StringBuilder sb = new StringBuilder(); - return sb; - } + for (RangerResourceDef resourceDef : serviceDef.getResources()) { + if (resourceDef == null || !exists(resourceDef.getName())) { + continue; + } - protected String getStringifiedValue() { return stringifiedValue; } + if (sb.length() > 0) { + sb.append(RESOURCE_SEP); + } - protected void setStringifiedValue(String val) { this.stringifiedValue = val; } + sb.append(resourceDef.getName()).append(RESOURCE_NAME_VAL_SEP).append(getValue(resourceDef.getName())); + } + + if (sb.length() > 0) { + ret = sb.toString(); + stringifiedCacheKeyValue = ret; + } + } + } + + return ret; + } + + @Override + public Map<String, Object> getAsMap() { + return elements == null ? Collections.emptyMap() : Collections.unmodifiableMap(elements); + } + + @Override + public RangerAccessResource getReadOnlyCopy() { + return new RangerAccessResourceReadOnly(this); + } + + @Override + public void setServiceDef(final RangerServiceDef serviceDef) { + this.serviceDef = serviceDef; + this.stringifiedValue = null; + this.stringifiedCacheKeyValue = null; + this.leafName = null; + } + + @Override + public void setOwnerUser(String ownerUser) { + this.ownerUser = ownerUser; + } + + @Override + public void setValue(String name, Object value) { + if (value == null) { + if (elements != null) { + elements.remove(name); + + if (elements.isEmpty()) { + elements = null; + } + } + } else { + if (elements == null) { + elements = new HashMap<>(); + } + elements.put(name, value); + } + + // reset, so that these will be computed again with updated elements + stringifiedValue = null; + stringifiedCacheKeyValue = null; + leafName = null; + } + + @Override + public int hashCode() { + int ret = 7; + + ret = 31 * ret + ObjectUtils.hashCode(ownerUser); + ret = 31 * ret + ObjectUtils.hashCode(elements); + + return ret; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof RangerAccessResourceImpl)) { + return false; + } + + if (this == obj) { + return true; + } + + RangerAccessResourceImpl other = (RangerAccessResourceImpl) obj; Review Comment: lines 240-243 may be simplified to: ` return ObjectUtils.equals(ownerUser, obj.ownerUser) && ObjectUtils.equals(elements, obj.elements);` ########## agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java: ########## @@ -58,1347 +48,1317 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +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; public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator { - private static final Logger LOG = LoggerFactory.getLogger(RangerDefaultPolicyEvaluator.class); - - private static final Logger PERF_POLICY_INIT_LOG = RangerPerfTracer.getPerfLogger("policy.init"); - private static final Logger PERF_POLICY_INIT_ACLSUMMARY_LOG = RangerPerfTracer.getPerfLogger("policy.init.ACLSummary"); - private static final Logger PERF_POLICY_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policy.request"); - private static final Logger PERF_POLICYCONDITION_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policycondition.request"); - - private List<RangerValidityScheduleEvaluator> validityScheduleEvaluators; - private List<RangerPolicyItemEvaluator> allowEvaluators; - private List<RangerPolicyItemEvaluator> denyEvaluators; - private List<RangerPolicyItemEvaluator> allowExceptionEvaluators; - private List<RangerPolicyItemEvaluator> denyExceptionEvaluators; - private int customConditionsCount; - private List<RangerDataMaskPolicyItemEvaluator> dataMaskEvaluators; - private List<RangerRowFilterPolicyItemEvaluator> rowFilterEvaluators; - private List<RangerConditionEvaluator> conditionEvaluators; - private String perfTag; - private PolicyACLSummary aclSummary = null; - private boolean disableRoleResolution = true; - - List<RangerPolicyItemEvaluator> getAllowEvaluators() { return allowEvaluators; } - List<RangerPolicyItemEvaluator> getAllowExceptionEvaluators() { return allowExceptionEvaluators; } - List<RangerPolicyItemEvaluator> getDenyEvaluators() { return denyEvaluators; } - List<RangerPolicyItemEvaluator> getDenyExceptionEvaluators() { return denyExceptionEvaluators; } - List<RangerDataMaskPolicyItemEvaluator> getDataMaskEvaluators() { return dataMaskEvaluators; } - List<RangerRowFilterPolicyItemEvaluator> getRowFilterEvaluators() { return rowFilterEvaluators; } - - @Override - public int getPolicyConditionsCount() { - return conditionEvaluators.size(); - } - - @Override - public int getCustomConditionsCount() { - return customConditionsCount; - } - - @Override - public int getValidityScheduleEvaluatorsCount() { - return validityScheduleEvaluators.size(); - } - - @Override - public void init(RangerPolicy policy, RangerServiceDef serviceDef, RangerPolicyEngineOptions options) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.init()"); - } - - StringBuilder perfTagBuffer = new StringBuilder(); - if (policy != null) { - perfTagBuffer.append("policyId=").append(policy.getId()).append(", policyName=").append(policy.getName()); - } - - perfTag = perfTagBuffer.toString(); - - RangerPerfTracer perf = null; - - if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_INIT_LOG)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_INIT_LOG, "RangerPolicyEvaluator.init(" + perfTag + ")"); - } - - super.init(policy, serviceDef, options); - - policy = getPolicy(); - - preprocessPolicy(policy, serviceDef, options); - - if(policy != null) { - validityScheduleEvaluators = createValidityScheduleEvaluators(policy); - - this.disableRoleResolution = options.disableRoleResolution; - - allowEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW); - - if (ServiceDefUtil.getOption_enableDenyAndExceptionsInPolicies(serviceDef, getPluginContext())) { - 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); - } else { - denyEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - allowExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - denyExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList(); - } - - dataMaskEvaluators = createDataMaskPolicyItemEvaluators(policy, serviceDef, options, policy.getDataMaskPolicyItems()); - rowFilterEvaluators = createRowFilterPolicyItemEvaluators(policy, serviceDef, options, policy.getRowFilterPolicyItems()); - conditionEvaluators = createPolicyConditionEvaluators(policy, serviceDef, options); - } 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(); - conditionEvaluators = Collections.<RangerConditionEvaluator>emptyList(); - } - - RangerPolicyItemEvaluator.EvalOrderComparator comparator = new RangerPolicyItemEvaluator.EvalOrderComparator(); - Collections.sort(allowEvaluators, comparator); - Collections.sort(denyEvaluators, comparator); - Collections.sort(allowExceptionEvaluators, comparator); - Collections.sort(denyExceptionEvaluators, comparator); - - /* dataMask, rowFilter policyItems must be evaulated in the order given in the policy; hence no sort - Collections.sort(dataMaskEvaluators); - Collections.sort(rowFilterEvaluators); - */ - - RangerPerfTracer.log(perf); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.init()"); - } - } - - @Override - public boolean isApplicable(Date accessTime) { - if (LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.isApplicable(" + accessTime + ")"); + private static final Logger LOG = LoggerFactory.getLogger(RangerDefaultPolicyEvaluator.class); + + private static final Logger PERF_POLICY_INIT_LOG = RangerPerfTracer.getPerfLogger("policy.init"); + private static final Logger PERF_POLICY_INIT_ACLSUMMARY_LOG = RangerPerfTracer.getPerfLogger("policy.init.ACLSummary"); + private static final Logger PERF_POLICY_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policy.request"); + private static final Logger PERF_POLICYCONDITION_REQUEST_LOG = RangerPerfTracer.getPerfLogger("policycondition.request"); + + private List<RangerValidityScheduleEvaluator> validityScheduleEvaluators; + private List<RangerPolicyItemEvaluator> allowEvaluators; + private List<RangerPolicyItemEvaluator> denyEvaluators; + private List<RangerPolicyItemEvaluator> allowExceptionEvaluators; + private List<RangerPolicyItemEvaluator> denyExceptionEvaluators; + private int customConditionsCount; + private List<RangerDataMaskPolicyItemEvaluator> dataMaskEvaluators; + private List<RangerRowFilterPolicyItemEvaluator> rowFilterEvaluators; + private List<RangerConditionEvaluator> conditionEvaluators; + private String perfTag; + private PolicyACLSummary aclSummary; + private boolean disableRoleResolution = true; + + static RangerPolicyItemAccess getAccess(RangerPolicyItem policyItem, String accessType) { + RangerPolicyItemAccess ret = null; + + if (policyItem != null && CollectionUtils.isNotEmpty(policyItem.getAccesses())) { + for (RangerPolicyItemAccess itemAccess : policyItem.getAccesses()) { + if (itemAccess != null && StringUtils.equalsIgnoreCase(itemAccess.getType(), accessType)) { + ret = itemAccess; + + break; + } + } + } + + return ret; + } + + @Override + public void init(RangerPolicy policy, RangerServiceDef serviceDef, RangerPolicyEngineOptions options) { + LOG.debug("==> RangerDefaultPolicyEvaluator.init()"); + + StringBuilder perfTagBuffer = new StringBuilder(); + if (policy != null) { + perfTagBuffer.append("policyId=").append(policy.getId()).append(", policyName=").append(policy.getName()); + } + + perfTag = perfTagBuffer.toString(); + + RangerPerfTracer perf = null; + + if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_INIT_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_INIT_LOG, "RangerPolicyEvaluator.init(" + perfTag + ")"); + } + + super.init(policy, serviceDef, options); + + policy = getPolicy(); + + preprocessPolicy(policy, serviceDef, options); + + if (policy != null) { + validityScheduleEvaluators = createValidityScheduleEvaluators(policy); + + this.disableRoleResolution = options.disableRoleResolution; + + allowEvaluators = createPolicyItemEvaluators(policy, serviceDef, options, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW); + + if (ServiceDefUtil.getOption_enableDenyAndExceptionsInPolicies(serviceDef, getPluginContext())) { + 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); + } else { + denyEvaluators = Collections.emptyList(); + allowExceptionEvaluators = Collections.emptyList(); + denyExceptionEvaluators = Collections.emptyList(); + } + + dataMaskEvaluators = createDataMaskPolicyItemEvaluators(policy, serviceDef, options, policy.getDataMaskPolicyItems()); + rowFilterEvaluators = createRowFilterPolicyItemEvaluators(policy, serviceDef, options, policy.getRowFilterPolicyItems()); + conditionEvaluators = createPolicyConditionEvaluators(policy, serviceDef, options); + } else { + validityScheduleEvaluators = Collections.emptyList(); + allowEvaluators = Collections.emptyList(); + denyEvaluators = Collections.emptyList(); + allowExceptionEvaluators = Collections.emptyList(); + denyExceptionEvaluators = Collections.emptyList(); + dataMaskEvaluators = Collections.emptyList(); + rowFilterEvaluators = Collections.emptyList(); + conditionEvaluators = Collections.emptyList(); + } + + RangerPolicyItemEvaluator.EvalOrderComparator comparator = new RangerPolicyItemEvaluator.EvalOrderComparator(); + allowEvaluators.sort(comparator); + denyEvaluators.sort(comparator); + allowExceptionEvaluators.sort(comparator); + denyExceptionEvaluators.sort(comparator); + + /* dataMask, rowFilter policyItems must be evaulated in the order given in the policy; hence no sort + Collections.sort(dataMaskEvaluators); + Collections.sort(rowFilterEvaluators); + */ + + RangerPerfTracer.log(perf); + + LOG.debug("<== RangerDefaultPolicyEvaluator.init()"); + } + + @Override + public PolicyACLSummary getPolicyACLSummary() { + if (aclSummary == null) { + aclSummary = createPolicyACLSummary(ServiceDefUtil.getExpandedImpliedGrants(getServiceDef()), true); + } + return aclSummary; + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerDefaultPolicyEvaluator={"); + + super.toString(sb); + + for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + + sb.append("resourceMatcher={"); + if (resourceMatcher != null) { + resourceMatcher.toString(sb); + } + sb.append("} "); } + sb.append("}"); + + return sb; + } + + @Override + public boolean isApplicable(Date accessTime) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isApplicable({})", accessTime); + boolean ret = false; if (accessTime != null && CollectionUtils.isNotEmpty(validityScheduleEvaluators)) { - for (RangerValidityScheduleEvaluator evaluator : validityScheduleEvaluators) { - if (evaluator.isApplicable(accessTime.getTime())) { - ret = true; - break; - } - } + for (RangerValidityScheduleEvaluator evaluator : validityScheduleEvaluators) { + if (evaluator.isApplicable(accessTime.getTime())) { + ret = true; + break; + } + } } else { - ret = true; + ret = true; + } + + LOG.debug("<== RangerDefaultPolicyEvaluator.isApplicable({}) : {}", accessTime, ret); + + return ret; + } + + @Override + public int getPolicyConditionsCount() { + return conditionEvaluators.size(); + } + + @Override + public int getCustomConditionsCount() { + return customConditionsCount; + } + + @Override + public int getValidityScheduleEvaluatorsCount() { + return validityScheduleEvaluators.size(); + } + + @Override + public void evaluate(RangerAccessRequest request, RangerAccessResult result) { + LOG.debug("==> RangerDefaultPolicyEvaluator.evaluate(policyId={}, {}, {})", getPolicyId(), request, result); + + RangerPerfTracer perf = null; + + if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_REQUEST_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.evaluate(requestHashCode=" + Integer.toHexString(System.identityHashCode(request)) + "," + + perfTag + ")"); + } + + if (request != null && result != null) { + for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + + if (!result.getIsAccessDetermined() || !result.getIsAuditedDetermined()) { + final RangerPolicyResourceMatcher.MatchType matchType; + + if (request instanceof RangerTagAccessRequest) { + matchType = ((RangerTagAccessRequest) request).getMatchType(); + } else { + matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE; + } + + final RangerAccessRequest.ResourceMatchingScope resourceMatchingScope = request.getResourceMatchingScope() != null ? request.getResourceMatchingScope() : RangerAccessRequest.ResourceMatchingScope.SELF; + final boolean isMatched; + + if (request.isAccessTypeAny() || resourceMatchingScope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS) { + isMatched = matchType == RangerPolicyResourceMatcher.MatchType.SELF || matchType == RangerPolicyResourceMatcher.MatchType.SELF_AND_ALL_DESCENDANTS || matchType == RangerPolicyResourceMatcher.MatchType.DESCENDANT; + } else { + isMatched = matchType == RangerPolicyResourceMatcher.MatchType.SELF || matchType == RangerPolicyResourceMatcher.MatchType.SELF_AND_ALL_DESCENDANTS; + } + + if (isMatched) { + //Evaluate Policy Level Custom Conditions, if any and allowed then go ahead for policyItem level evaluation + if (matchPolicyCustomConditions(request)) { + if (!result.getIsAuditedDetermined()) { + if (isAuditEnabled()) { + result.setIsAudited(true); + result.setAuditPolicyId(getPolicyId()); + } + } + if (!result.getIsAccessDetermined()) { + if (hasMatchablePolicyItem(request)) { + evaluatePolicyItems(request, matchType, result); + } + } + } + } + } + } + } + + RangerPerfTracer.log(perf); + + LOG.debug("<== RangerDefaultPolicyEvaluator.evaluate(policyId={}, {}, {})", getPolicyId(), request, result); + } + + @Override + public boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isMatch(policy-id={}, {}, {})", getPolicyId(), resource, evalContext); + + boolean ret = false; + + RangerPerfTracer perf = null; + + if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_REQUEST_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.isMatch(resource=" + resource.getAsString() + "," + evalContext + "," + perfTag + ")"); + } + + for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + + ret = resourceMatcher != null && resourceMatcher.isMatch(resource, evalContext); + + if (ret) { + break; + } + } + + RangerPerfTracer.log(perf); + + LOG.debug("<== RangerDefaultPolicyEvaluator.isMatch(policy-id={}, {}, {}) : {}", getPolicyId(), resource, evalContext, ret); + + return ret; + } + + @Override + public boolean isCompleteMatch(RangerAccessResource resource, Map<String, Object> evalContext) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isCompleteMatch({}, {})", resource, evalContext); + + final boolean ret; + + List<RangerPolicyResourceEvaluator> resourceEvaluators = getResourceEvaluators(); + + if (resourceEvaluators.size() == 1) { + RangerPolicyResourceEvaluator resourceEvaluator = resourceEvaluators.get(0); + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + + ret = resourceMatcher != null && resourceMatcher.isCompleteMatch(resource, evalContext); + } else { + ret = false; + } + + LOG.debug("<== RangerDefaultPolicyEvaluator.isCompleteMatch({}): {}", resource, ret); + + return ret; + } + + @Override + public boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, List<Map<String, RangerPolicyResource>> additionalResources, Map<String, Object> evalContext) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isCompleteMatch({}, {})", resources, evalContext); + + boolean ret = false; + + List<RangerPolicyResourceEvaluator> resourceEvaluators = getResourceEvaluators(); + + for (int i = 0; i < resourceEvaluators.size(); i++) { + RangerPolicyResourceEvaluator resourceEvaluator = resourceEvaluators.get(i); + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + Map<String, RangerPolicyResource> policyResource = null; + + if (i == 0) { + policyResource = resources; + } else if (additionalResources != null && additionalResources.size() >= i) { + policyResource = additionalResources.get(i - 1); + } + + ret = resourceMatcher != null && policyResource != null && resourceMatcher.isCompleteMatch(policyResource, evalContext); + + if (!ret) { + break; + } + } + + LOG.debug("<== RangerDefaultPolicyEvaluator.isCompleteMatch({}, {}): {}", resources, evalContext, ret); + + return ret; + } + + @Override + public boolean isAccessAllowed(Map<String, RangerPolicyResource> resources, List<Map<String, RangerPolicyResource>> additionalResources, String user, Set<String> userGroups, String accessType) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed({}, {}, {}, {})", resources, user, userGroups, accessType); + + boolean ret = isAccessAllowed(user, userGroups, null, null, accessType) && isMatch(resources, null); + + if (ret && additionalResources != null) { + for (Map<String, RangerPolicyResource> additionalResource : additionalResources) { + ret = isMatch(additionalResource, null); + + if (!ret) { + break; + } + } + } + + LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed({}, {}, {}, {}): {}", resources, user, userGroups, accessType, ret); + + return ret; + } + + @Override + public void updateAccessResult(RangerAccessResult result, RangerPolicyResourceMatcher.MatchType matchType, boolean isAllowed, String reason) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.updateAccessResult({}, {}, {}, {}, {})", result, matchType, isAllowed, reason, getPolicyId()); + } + + if (!isAllowed) { + if (matchType != RangerPolicyResourceMatcher.MatchType.DESCENDANT || !result.getAccessRequest().ignoreDescendantDeny()) { + result.setIsAllowed(false); + result.setPolicyPriority(getPolicyPriority()); + result.setPolicyId(getPolicyId()); + result.setReason(reason); + result.setPolicyVersion(getPolicy().getVersion()); + } + } else { + if (!result.getIsAllowed()) { // if access is not yet allowed by another policy + result.setIsAllowed(true); + result.setPolicyPriority(getPolicyPriority()); + result.setPolicyId(getPolicyId()); + result.setReason(reason); + result.setPolicyVersion(getPolicy().getVersion()); + } } if (LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.isApplicable(" + accessTime + ") : " + ret); + LOG.debug("<== RangerDefaultPolicyEvaluator.updateAccessResult({}, {}, {}, {}, {})", result, matchType, isAllowed, reason, getPolicyId()); + } + } + + @Override + public void getResourceAccessInfo(RangerAccessRequest request, RangerResourceAccessInfo result) { + LOG.debug("==> RangerDefaultPolicyEvaluator.getResourceAccessInfo({}, {})", request, result); + + for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + RangerPolicyResourceMatcher.MatchType matchType; + + if (request instanceof RangerTagAccessRequest) { + matchType = ((RangerTagAccessRequest) request).getMatchType(); + } else { + matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE; + } + + final boolean isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE; + + if (isMatched) { + if (CollectionUtils.isNotEmpty(allowEvaluators)) { + Set<String> users = new HashSet<>(); + Set<String> groups = new HashSet<>(); + + getResourceAccessInfo(request, allowEvaluators, users, groups); + + if (CollectionUtils.isNotEmpty(allowExceptionEvaluators)) { + Set<String> exceptionUsers = new HashSet<>(); + Set<String> exceptionGroups = new HashSet<>(); + + getResourceAccessInfo(request, allowExceptionEvaluators, exceptionUsers, exceptionGroups); + + users.removeAll(exceptionUsers); + groups.removeAll(exceptionGroups); + } + + result.getAllowedUsers().addAll(users); + result.getAllowedGroups().addAll(groups); + } + if (matchType != RangerPolicyResourceMatcher.MatchType.DESCENDANT) { + if (CollectionUtils.isNotEmpty(denyEvaluators)) { + Set<String> users = new HashSet<>(); + Set<String> groups = new HashSet<>(); + + getResourceAccessInfo(request, denyEvaluators, users, groups); + + if (CollectionUtils.isNotEmpty(denyExceptionEvaluators)) { + Set<String> exceptionUsers = new HashSet<>(); + Set<String> exceptionGroups = new HashSet<>(); + + getResourceAccessInfo(request, denyExceptionEvaluators, exceptionUsers, exceptionGroups); + + users.removeAll(exceptionUsers); + groups.removeAll(exceptionGroups); + } + + result.getDeniedUsers().addAll(users); + result.getDeniedGroups().addAll(groups); + } + } + } + } + + LOG.debug("<== RangerDefaultPolicyEvaluator.getResourceAccessInfo({}, {})", request, result); + } + + @Override + public Set<String> getAllowedAccesses(RangerAccessResource resource, String user, Set<String> userGroups, Set<String> roles, Set<String> accessTypes) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.getAllowedAccesses(policy-id={}, {}, {}, {}, {}, {})", getPolicyId(), resource, user, userGroups, roles, accessTypes); + } + + Set<String> ret = null; + + Map<String, Object> evalContext = new HashMap<>(); + + RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user); + + if (isMatch(resource, evalContext)) { + ret = new HashSet<>(); + + for (String accessType : accessTypes) { + if (isAccessAllowed(user, userGroups, roles, resource.getOwnerUser(), accessType)) { + ret.add(accessType); + } + } + } else { + LOG.debug("RangerDefaultPolicyEvaluator.getAllowedAccesses - Not Matched -- (policy-id={}, {}, {}, {}, {}, {})", getPolicyId(), resource, user, userGroups, roles, accessTypes); + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.getAllowedAccesses(policy-id={}, {}, {}, {}, {}, {}): {}", getPolicyId(), resource, user, userGroups, roles, accessTypes, ret); } return ret; } @Override - public void evaluate(RangerAccessRequest request, RangerAccessResult result) { + public Set<String> getAllowedAccesses(Map<String, RangerPolicyResource> resources, String user, Set<String> userGroups, Set<String> roles, Set<String> accessTypes, Map<String, Object> evalContext) { if (LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.evaluate(policyId=" + getPolicyId() + ", " + request + ", " + result + ")"); + LOG.debug("==> RangerDefaultPolicyEvaluator.getAllowedAccesses({}, {}, {}, {}, {}, {})", getPolicyId(), user, userGroups, roles, accessTypes, evalContext); } - RangerPerfTracer perf = null; + Set<String> ret = null; - if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_REQUEST_LOG)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.evaluate(requestHashCode=" + Integer.toHexString(System.identityHashCode(request)) + "," - + perfTag + ")"); - } + if (isMatch(resources, evalContext)) { + if (CollectionUtils.isNotEmpty(accessTypes)) { + ret = new HashSet<>(); + for (String accessType : accessTypes) { + if (isAccessAllowed(user, userGroups, roles, null, accessType)) { + ret.add(accessType); + } + } + } else { + if (isAccessAllowed(user, userGroups, roles, null, null)) { + ret = new HashSet<>(); + } + } + } - if (request != null && result != null) { - for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { - RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); - - if (!result.getIsAccessDetermined() || !result.getIsAuditedDetermined()) { - final RangerPolicyResourceMatcher.MatchType matchType; - - if (request instanceof RangerTagAccessRequest) { - matchType = ((RangerTagAccessRequest) request).getMatchType(); - } else { - matchType = resourceMatcher != null ? resourceMatcher.getMatchType(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()) : RangerPolicyResourceMatcher.MatchType.NONE; - } - - final RangerAccessRequest.ResourceMatchingScope resourceMatchingScope = request.getResourceMatchingScope() != null ? request.getResourceMatchingScope() : RangerAccessRequest.ResourceMatchingScope.SELF; - final boolean isMatched; - - if (request.isAccessTypeAny() || resourceMatchingScope == RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS) { - isMatched = matchType == RangerPolicyResourceMatcher.MatchType.SELF || matchType == RangerPolicyResourceMatcher.MatchType.SELF_AND_ALL_DESCENDANTS || matchType == RangerPolicyResourceMatcher.MatchType.DESCENDANT; - } else { - isMatched = matchType == RangerPolicyResourceMatcher.MatchType.SELF || matchType == RangerPolicyResourceMatcher.MatchType.SELF_AND_ALL_DESCENDANTS; - } - - if (isMatched) { - //Evaluate Policy Level Custom Conditions, if any and allowed then go ahead for policyItem level evaluation - if (matchPolicyCustomConditions(request)) { - if (!result.getIsAuditedDetermined()) { - if (isAuditEnabled()) { - result.setIsAudited(true); - result.setAuditPolicyId(getPolicyId()); - } - } - if (!result.getIsAccessDetermined()) { - if (hasMatchablePolicyItem(request)) { - evaluatePolicyItems(request, matchType, result); - } - } - } - } - } - } - } - - RangerPerfTracer.log(perf); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.evaluate(policyId=" + getPolicyId() + ", " + request + ", " + result + ")"); + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.getAllowedAccesses({}, {}, {}, {}, {}, {}): {}", getPolicyId(), user, userGroups, roles, accessTypes, evalContext, ret); + } + + return ret; + } + /* + * This is used only by test code + */ + + protected void evaluatePolicyItems(RangerAccessRequest request, RangerPolicyResourceMatcher.MatchType matchType, RangerAccessResult result) { + LOG.debug("==> RangerDefaultPolicyEvaluator.evaluatePolicyItems({}, {}, {})", request, result, matchType); + + Set<String> allRequestedAccesses = RangerAccessRequestUtil.getAllRequestedAccessTypes(request); + + if (CollectionUtils.isNotEmpty(allRequestedAccesses)) { + Map<String, RangerAccessResult> accessTypeResults = RangerAccessRequestUtil.getAccessTypeResults(request); + + for (String accessType : allRequestedAccesses) { + LOG.debug("Checking for accessType:[{}]", accessType); + + RangerAccessResult denyResult = null; + RangerAccessResult allowResult = null; + boolean noResult = false; + + RangerAccessRequestWrapper oneRequest = new RangerAccessRequestWrapper(request, accessType); + RangerAccessResult oneResult = new RangerAccessResult(result.getPolicyType(), result.getServiceName(), result.getServiceDef(), oneRequest); + + oneResult.setAuditResultFrom(result); + + RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(oneRequest, oneResult); + + if (matchedPolicyItem != null) { + matchedPolicyItem.updateAccessResult(this, oneResult, matchType); + } else if (getPolicy().getIsDenyAllElse() && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + updateAccessResult(oneResult, matchType, false, "matched deny-all-else policy"); + } + + if (oneResult.getIsAllowed()) { + allowResult = oneResult; + } else if (oneResult.getIsAccessDetermined()) { + denyResult = oneResult; + } else { + noResult = true; + } + + if (!noResult) { + RangerAccessResult oldResult = accessTypeResults.get(accessType); + if (oldResult == null) { + accessTypeResults.put(accessType, allowResult != null ? allowResult : denyResult); + } else { + int oldPriority = oldResult.getPolicyPriority(); + if (oldResult.getIsAllowed()) { + if (denyResult != null) { + if (getPolicyPriority() >= oldPriority) { + accessTypeResults.put(accessType, denyResult); + } + } else { + if (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS) { + if (getPolicyPriority() > oldPriority) { + accessTypeResults.put(accessType, allowResult); + } + } else { + if (getPolicyPriority() >= oldPriority) { + accessTypeResults.put(accessType, allowResult); + } + } + } + } else { // Earlier evaluator denied this access + if (getPolicyPriority() >= oldPriority && allowResult != null && (oneRequest.isAccessTypeAny() || RangerAccessRequestUtil.getIsAnyAccessInContext(oneRequest.getContext()))) { + accessTypeResults.put(accessType, allowResult); + } else { + if (getPolicyPriority() > oldPriority && denyResult != null) { + accessTypeResults.put(accessType, denyResult); + } + } + } + } + /* At least one access is allowed or denied - this evaluator need not be checked for other accesses as the test below + * implies that there is only one access group in the request + */ + if (oneRequest.isAccessTypeAny() || RangerAccessRequestUtil.getIsAnyAccessInContext(oneRequest.getContext())) { + if (oneRequest.ignoreDescendantDeny() && allowResult != null) { + break; + } else if (!oneRequest.ignoreDescendantDeny() && denyResult != null) { + break; + } + } + } + } + + RangerAccessResult compositeAccessResult = getCompositeAccessResult(request, result); + if (compositeAccessResult != null) { + result.setAccessResultFrom(compositeAccessResult); + } + } else { + RangerPolicyItemEvaluator matchedPolicyItem = getMatchingPolicyItem(request, result); + if (matchedPolicyItem != null) { + matchedPolicyItem.updateAccessResult(this, result, matchType); + } else if (getPolicy().getIsDenyAllElse() && (getPolicy().getPolicyType() == null || getPolicy().getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS)) { + updateAccessResult(result, matchType, false, "matched deny-all-else policy"); + } } + + LOG.debug("<== RangerDefaultPolicyEvaluator.evaluatePolicyItems({}, {}, {})", request, result, matchType); } - @Override - public boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.isMatch(policy-id=" + getPolicyId() + ", " + resource + ", " + evalContext + ")"); - } + protected RangerPolicyItemEvaluator getDeterminingPolicyItem(String user, Set<String> userGroups, Set<String> roles, String owner, String accessType) { + LOG.debug("==> RangerDefaultPolicyEvaluator.getDeterminingPolicyItem({}, {}, {}, {}, {})", user, userGroups, roles, owner, accessType); + + RangerPolicyItemEvaluator ret; - boolean ret = false; + /* + * 1. if a deny matches without hitting any deny-exception, return that + * 2. if an allow matches without hitting any allow-exception, return that + */ + ret = getMatchingPolicyItem(user, userGroups, roles, owner, accessType, denyEvaluators, denyExceptionEvaluators); - RangerPerfTracer perf = null; + if (ret == null) { + ret = getMatchingPolicyItem(user, userGroups, roles, owner, accessType, allowEvaluators, allowExceptionEvaluators); + } - if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_REQUEST_LOG)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.isMatch(resource=" + resource.getAsString() + "," + evalContext + "," + perfTag + ")"); - } + LOG.debug("<== RangerDefaultPolicyEvaluator.getDeterminingPolicyItem({}, {}, {}, {}, {}): {}", user, userGroups, roles, owner, accessType, ret); - for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { - RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + return ret; + } - ret = resourceMatcher != null && resourceMatcher.isMatch(resource, evalContext); + /* + 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. + */ - if (ret) { - break; - } - } + protected boolean isMatch(RangerPolicy policy, Map<String, Object> evalContext) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isMatch({}, {})", policy.getId(), evalContext); - RangerPerfTracer.log(perf); + final boolean ret = isMatch(policy.getResources(), evalContext); - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.isMatch(policy-id=" + getPolicyId() + ", " + resource + ", " + evalContext + ") : " + ret); - } + LOG.debug("<== RangerDefaultPolicyEvaluator.isMatch({}, {}): {}", policy.getId(), evalContext, ret); - return ret; - } + return ret; + } - @Override - public boolean isCompleteMatch(RangerAccessResource resource, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.isCompleteMatch(" + resource + ", " + evalContext + ")"); - } + protected boolean isMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isMatch({}, {})", resources, evalContext); - final boolean ret; + boolean ret = false; - List<RangerPolicyResourceEvaluator> resourceEvaluators = getResourceEvaluators(); + for (RangerPolicyResourceEvaluator resourceEvaluator : getResourceEvaluators()) { + RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); - if (resourceEvaluators.size() == 1) { - RangerPolicyResourceEvaluator resourceEvaluator = resourceEvaluators.get(0); - RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); + ret = resourceMatcher != null && resourceMatcher.isMatch(resources, evalContext); - ret = resourceMatcher != null && resourceMatcher.isCompleteMatch(resource, evalContext); - } else { - ret = false; - } + if (ret) { + break; + } + } - if(LOG.isDebugEnabled()) { - LOG.debug("<== RangerDefaultPolicyEvaluator.isCompleteMatch(" + resource + "): " + ret); - } - - return ret; - } - - @Override - public boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, List<Map<String, RangerPolicyResource>> additionalResources, Map<String, Object> evalContext) { - if(LOG.isDebugEnabled()) { - LOG.debug("==> RangerDefaultPolicyEvaluator.isCompleteMatch(" + resources + ", " + evalContext + ")"); - } + LOG.debug("<== RangerDefaultPolicyEvaluator.isMatch({}, {}): {}", resources, evalContext, ret); - boolean ret = false; - - List<RangerPolicyResourceEvaluator> resourceEvaluators = getResourceEvaluators(); + return ret; + } - for (int i = 0; i < resourceEvaluators.size(); i++) { - RangerPolicyResourceEvaluator resourceEvaluator = resourceEvaluators.get(i); - RangerPolicyResourceMatcher resourceMatcher = resourceEvaluator.getPolicyResourceMatcher(); - Map<String, RangerPolicyResource> policyResource = null; - - if (i == 0) { - policyResource = resources; - } else if (additionalResources != null && additionalResources.size() >= i) { - policyResource = additionalResources.get(i - 1); - } - - ret = resourceMatcher != null && policyResource != null && resourceMatcher.isCompleteMatch(policyResource, evalContext); + /* + 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. + */ + + protected boolean isAccessAllowed(String user, Set<String> userGroups, Set<String> roles, String owner, String accessType) { + if (LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(policy-id={}, {}, {}, {}, {}, {})", getPolicyId(), user, userGroups, roles, owner, accessType); + } + + boolean ret = false; + + RangerPerfTracer perf = null; + + if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_REQUEST_LOG)) { + perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_REQUEST_LOG, "RangerPolicyEvaluator.isAccessAllowed(hashCode=" + Integer.toHexString(System.identityHashCode(this)) + "," + perfTag + ")"); + } + + if (LOG.isDebugEnabled()) { + LOG.debug("Using policyItemEvaluators for checking if access is allowed. PolicyId=[{}]", getPolicyId()); + } + + RangerPolicyItemEvaluator item = this.getDeterminingPolicyItem(user, userGroups, roles, owner, accessType); + + if (item != null && item.getPolicyItemType() == RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW) { + ret = true; + } + + RangerPerfTracer.log(perf); + + if (LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(policy-id={}, {}, {}, {}, {}, {}): {}", getPolicyId(), user, userGroups, roles, owner, accessType, ret); + } + + return ret; + } + + protected void preprocessPolicy(RangerPolicy policy, RangerServiceDef serviceDef, RangerPolicyEngineOptions options) { + if (policy == null || (!hasAllow() && !hasDeny()) || serviceDef == null) { + return; + } + + /* Review Comment: may be the commented lines can be removed, not sure. ########## agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerValidityScheduleEvaluator.java: ########## @@ -584,5 +529,43 @@ private ValueWithBorrow getPastFieldValueWithBorrow(RangerValidityRecurrence.Rec } return ret; } + + private static class ValueWithBorrow { + int value; + boolean borrow; + + ValueWithBorrow() { + } + + ValueWithBorrow(int value) { + this(value, false); + } + + ValueWithBorrow(int value, boolean borrow) { + this.value = value; + this.borrow = borrow; + } + + @Override + public String toString() { Review Comment: nit: toString() may be the last function in a class. ########## agents-common/src/main/java/org/apache/ranger/plugin/policyresourcematcher/RangerDefaultPolicyResourceMatcher.java: ########## @@ -73,41 +71,48 @@ public RangerDefaultPolicyResourceMatcher(boolean forceEnableWildcardMatch) { this.forceEnableWildcardMatch = forceEnableWildcardMatch; } - @Override - public void setServiceDef(RangerServiceDef serviceDef) { - if (isInitialized) { - LOG.warn("RangerDefaultPolicyResourceMatcher is already initialized. init() must be done again after updating serviceDef"); + public static boolean isHierarchyValidForResources(List<RangerResourceDef> hierarchy, Map<String, ?> resources) { + if (LOG.isDebugEnabled()) { Review Comment: nit: please check for occurrences of isDebugEnabled in this file. ########## agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerValidityScheduleEvaluator.java: ########## @@ -96,11 +92,37 @@ public RangerValidityScheduleEvaluator(String startTimeStr, String endTimeStr, S } } - public boolean isApplicable(long accessTime) { + public static long getAdjustedTime(long localTime, TimeZone timeZone) { + long ret = localTime; + + if (LOG.isDebugEnabled()) { Review Comment: nit: please check for occurrences of isDebugEnabled in this file. ########## agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestCacheMap.java: ########## @@ -28,89 +28,79 @@ import java.util.Set; public class TestCacheMap { - private static final Logger LOG = LoggerFactory.getLogger(TestCacheMap.class); - private static CacheMap<String, String> testCacheMap; - private static int initialCapacity = 16; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - if(LOG.isDebugEnabled()) { - LOG.debug("==> TestCacheMap.setUpBeforeClass(), initialCapacity:" + initialCapacity); - } - - testCacheMap = new CacheMap<String, String>(initialCapacity); - - if(LOG.isDebugEnabled()) { - LOG.debug("<== TestCacheMap.setUpBeforeClass(), initialCapacity:" + initialCapacity); - } - } - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Test - public void runTests() { - - if(LOG.isDebugEnabled()) { - LOG.debug("==> TestCacheMap.runTests(), First batch of " + initialCapacity + " inserts starting from 0"); - } - for (int i = 0; i < initialCapacity; i++) { - String key = String.valueOf(i); - String value = key; - - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Inserting into Cache, key:" + key + ", value:" + value); - } - testCacheMap.put(key, value); - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Cache Size after insert(): " + testCacheMap.size()); - } - } - - if(LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), First batch of " + initialCapacity/2 + " retrieves counting down from " + (initialCapacity/2-1)); - } - - for (int i = initialCapacity/2 - 1; i >= 0; i--) { - String key = String.valueOf(i); - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Searching Cache, key:" + key); - } - String value = testCacheMap.get(key); - if (value == null || !value.equals(key)) { - LOG.error("TestCacheMap.runTests(), Did not get correct value for key, key:" + key + ", value:" + value); - } - } - if(LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Second batch of " + initialCapacity/2 + " inserts starting from " + initialCapacity); - } - for (int i = initialCapacity; i < initialCapacity+initialCapacity/2; i++) { - String key = String.valueOf(i); - String value = key; - - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Inserting into Cache, key:" + key + ", value:" + value); - } - testCacheMap.put(key, value); - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), Cache Size after insert(): " + testCacheMap.size()); - } - } - - Set<String> keySet = testCacheMap.keySet(); - - if (LOG.isDebugEnabled()) { - LOG.debug("TestCacheMap.runTests(), KeySet Size:" + keySet.size()); - LOG.debug("TestCacheMap.runTests(), printing keys.."); - - int i = 0; - - for (String key : keySet) { - LOG.debug("TestCacheMap.runTests(), index:" + i++ + ", key:" + key); - } - - LOG.debug("<== TestCacheMap.runTests()"); - } - - } + private static final Logger LOG = LoggerFactory.getLogger(TestCacheMap.class); + + private static CacheMap<String, String> testCacheMap; + private static final int initialCapacity = 16; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + LOG.debug("==> TestCacheMap.setUpBeforeClass(), initialCapacity:{}", initialCapacity); + + testCacheMap = new CacheMap<>(initialCapacity); + + LOG.debug("<== TestCacheMap.setUpBeforeClass(), initialCapacity:{}", initialCapacity); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void runTests() { + LOG.debug("==> TestCacheMap.runTests(), First batch of {} inserts starting from 0", initialCapacity); + + for (int i = 0; i < initialCapacity; i++) { + String key = String.valueOf(i); + String value = key; + + LOG.debug("TestCacheMap.runTests(), Inserting into Cache, key:{}, value:{}", key, value); + + testCacheMap.put(key, value); + + LOG.debug("TestCacheMap.runTests(), Cache Size after insert(): {}", testCacheMap.size()); + } + + LOG.debug("TestCacheMap.runTests(), First batch of {} retrieves counting down from {}", initialCapacity / 2, (initialCapacity / 2 - 1)); + + for (int i = initialCapacity / 2 - 1; i >= 0; i--) { + String key = String.valueOf(i); + + LOG.debug("TestCacheMap.runTests(), Searching Cache, key:{}", key); + + String value = testCacheMap.get(key); + + if (value == null || !value.equals(key)) { + LOG.error("TestCacheMap.runTests(), Did not get correct value for key, key:{}, value:{}", key, value); + } + } + + LOG.debug("TestCacheMap.runTests(), Second batch of {} inserts starting from {}", initialCapacity / 2, initialCapacity); + + for (int i = initialCapacity; i < initialCapacity + initialCapacity / 2; i++) { + String key = String.valueOf(i); + String value = key; + + LOG.debug("TestCacheMap.runTests(), Inserting into Cache, key:{}, value:{}", key, value); + + testCacheMap.put(key, value); + + LOG.debug("TestCacheMap.runTests(), Cache Size after insert(): {}", testCacheMap.size()); + } + + Set<String> keySet = testCacheMap.keySet(); + + if (LOG.isDebugEnabled()) { Review Comment: nit: isDebugEnabled may be removed. ########## agents-common/src/main/java/org/apache/ranger/plugin/util/CachedResourceEvaluators.java: ########## @@ -41,46 +41,15 @@ import java.util.Set; public class CachedResourceEvaluators { - private final Map<String, Map<Map<String, RangerAccessRequest.ResourceElementMatchingScope>, Collection<RangerServiceResourceMatcher>>> cache = new HashMap<>(); - private final RangerReadWriteLock cacheLock = new RangerReadWriteLock(true); - - private static final Logger LOG = LoggerFactory.getLogger(CachedResourceEvaluators.class); - private static final Logger PERF_EVALUATORS_RETRIEVAL_LOG = RangerPerfTracer.getPerfLogger("CachedResourceEvaluators.retrieval"); + private static final Logger LOG = LoggerFactory.getLogger(CachedResourceEvaluators.class); + private static final Logger PERF_EVALUATORS_RETRIEVAL_LOG = RangerPerfTracer.getPerfLogger("CachedResourceEvaluators.retrieval"); + private final Map<String, Map<Map<String, RangerAccessRequest.ResourceElementMatchingScope>, Collection<RangerServiceResourceMatcher>>> cache = new HashMap<>(); Review Comment: we may keep a line space here. ########## agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java: ########## @@ -25,1375 +25,1481 @@ import org.apache.ranger.authorization.utils.JsonUtils; import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.contextenricher.RangerTagForEval; +import org.apache.ranger.plugin.util.JavaScriptEdits; import org.apache.ranger.plugin.util.MacroProcessor; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.RangerPerfTracer; import org.apache.ranger.plugin.util.RangerTimeRangeChecker; import org.apache.ranger.plugin.util.RangerUserStore; -import org.apache.ranger.plugin.util.JavaScriptEdits; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptException; + import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +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.Objects; +import java.util.Set; +import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.apache.ranger.plugin.util.RangerCommonConstants.*; - +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACCESS_TIME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACCESS_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACTION; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLIENT_IP_ADDRESS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLIENT_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLUSTER_NAME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLUSTER_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_FORWARDED_ADDRESSES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REMOTE_IP_ADDRESS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REQUEST; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REQUEST_DATA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_RESOURCE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAGS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_UGA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_ATTRIBUTES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_GROUPS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_GROUP_ATTRIBUTES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_ROLES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__MATCH_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__NAME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__OWNER_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_ANY_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_NO_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_TAG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_UG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_USER_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_AFTER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_BEFORE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_BETWEEN; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ANY_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ANY_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_NOT_IN_ANY_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_NOT_IN_ANY_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_USER_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_USER_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_POLYFILL_INCLUDES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_POLYFILL_INTERSECTS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_REQ; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_RES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAGNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAGS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UGA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UGNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_URNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR__CTX; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR__CTX_JSON; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_ctx; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_tag; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_tagAttr; public final class RangerRequestScriptEvaluator { - private static final Logger LOG = LoggerFactory.getLogger(RangerRequestScriptEvaluator.class); - - private static final Logger PERF_POLICY_CONDITION_SCRIPT_TOJSON = RangerPerfTracer.getPerfLogger("policy.condition.script.tojson"); - private static final Logger PERF_POLICY_CONDITION_SCRIPT_EVAL = RangerPerfTracer.getPerfLogger("policy.condition.script.eval"); - private static final String TAG_ATTR_DATE_FORMAT_PROP = "ranger.plugin.tag.attr.additional.date.formats"; - private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR = "||"; - private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX = "\\|\\|"; - private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy/MM/dd"; - private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME = "ATLAS_DATE_FORMAT"; - private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; - private static final String SCRIPT_SAFE_PREEXEC = "exit=null;quit=null;"; - private static final String SCRIPT_PREEXEC = SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + "); J=JSON.stringify;" + - SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" + - SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" + - SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" + - SCRIPT_VAR_UGNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" + - SCRIPT_VAR_UG + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" + - SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" + - SCRIPT_VAR_URNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" + - SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" + - SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" + - SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";"; - private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern()); - private static final Pattern USER_ATTRIBUTES_PATTERN = Pattern.compile(getUserAttributesPattern()); - private static final Pattern GROUP_ATTRIBUTES_PATTERN = Pattern.compile(getGroupAttributesPattern()); - private static final String STR_QUOTE = "'"; - private static final String STR_COMMA = ","; - - private static final MacroProcessor MACRO_PROCESSOR = new MacroProcessor(getMacrosMap()); - - private static String[] dateFormatStrings = null; - - private final RangerAccessRequest accessRequest; - private final ScriptEngine scriptEngine; - private final Bindings bindings; - private boolean initDone = false; - private Map<String, String> userAttrs = Collections.emptyMap(); - private Map<String, Map<String, String>> groupAttrs = Collections.emptyMap(); - private Map<String, Map<String, Object>> tags = Collections.emptyMap(); - private Map<String, Object> tag = Collections.emptyMap(); - private Collection<String> userGroups = Collections.emptySet(); - private Collection<String> userRoles = Collections.emptySet(); - private Collection<String> tagNames = Collections.emptySet(); - private Boolean result = false; - - static { - init(null); - } - - private static final ThreadLocal<List<SimpleDateFormat>> THREADLOCAL_DATE_FORMATS = - new ThreadLocal<List<SimpleDateFormat>>() { - @Override protected List<SimpleDateFormat> initialValue() { - List<SimpleDateFormat> ret = new ArrayList<>(); - - for (String dateFormatString : dateFormatStrings) { - try { - if (StringUtils.isNotBlank(dateFormatString)) { - if (StringUtils.equalsIgnoreCase(dateFormatString, DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME)) { - dateFormatString = DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT; - } - SimpleDateFormat df = new SimpleDateFormat(dateFormatString); - df.setLenient(false); - ret.add(df); - } - } catch (Exception exception) { - // Ignore - } - } - - return ret; - } - }; - - - public static boolean needsJsonCtxEnabled(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasUserAttributeReference(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = USER_ATTRIBUTES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasGroupAttributeReference(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = GROUP_ATTRIBUTES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasUserGroupAttributeReference(String script) { - return hasUserAttributeReference(script) || hasGroupAttributeReference(script); - } - - public static boolean hasUserGroupAttributeReference(Collection<String> scripts) { - boolean ret = false; - - if (scripts != null) { - for (String script : scripts) { - if (hasUserGroupAttributeReference(script)) { - ret = true; - - break; - } - } - } + private static final Logger LOG = LoggerFactory.getLogger(RangerRequestScriptEvaluator.class); + + private static final Logger PERF_POLICY_CONDITION_SCRIPT_TOJSON = RangerPerfTracer.getPerfLogger("policy.condition.script.tojson"); + private static final Logger PERF_POLICY_CONDITION_SCRIPT_EVAL = RangerPerfTracer.getPerfLogger("policy.condition.script.eval"); + private static final String TAG_ATTR_DATE_FORMAT_PROP = "ranger.plugin.tag.attr.additional.date.formats"; + private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR = "||"; + private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX = "\\|\\|"; + private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy/MM/dd"; + private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME = "ATLAS_DATE_FORMAT"; + private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static final String SCRIPT_SAFE_PREEXEC = "exit=null;quit=null;"; + private static final String SCRIPT_PREEXEC = SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + "); J=JSON.stringify;" + + SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" + + SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" + + SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" + + SCRIPT_VAR_UGNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" + + SCRIPT_VAR_UG + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" + + SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" + + SCRIPT_VAR_URNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" + + SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" + + SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" + + SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";"; + private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern()); + private static final Pattern USER_ATTRIBUTES_PATTERN = Pattern.compile(getUserAttributesPattern()); + private static final Pattern GROUP_ATTRIBUTES_PATTERN = Pattern.compile(getGroupAttributesPattern()); + private static final String STR_QUOTE = "'"; + private static final String STR_COMMA = ","; + + private static final MacroProcessor MACRO_PROCESSOR = new MacroProcessor(getMacrosMap()); + + private static String[] dateFormatStrings = {}; + private static final ThreadLocal<List<SimpleDateFormat>> THREADLOCAL_DATE_FORMATS = ThreadLocal.withInitial(() -> { + List<SimpleDateFormat> ret = new ArrayList<>(); + + for (String dateFormatString : dateFormatStrings) { + try { + if (StringUtils.isNotBlank(dateFormatString)) { + if (StringUtils.equalsIgnoreCase(dateFormatString, DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME)) { + dateFormatString = DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT; + } + SimpleDateFormat df = new SimpleDateFormat(dateFormatString); + df.setLenient(false); + ret.add(df); + } + } catch (Exception exception) { + // Ignore + } + } + + return ret; + }); + + private final RangerAccessRequest accessRequest; + private final ScriptEngine scriptEngine; + private final Bindings bindings; + private boolean initDone; + private Map<String, String> userAttrs = Collections.emptyMap(); + private Map<String, Map<String, String>> groupAttrs = Collections.emptyMap(); + private Map<String, Map<String, Object>> tags = Collections.emptyMap(); + private Map<String, Object> tag = Collections.emptyMap(); + private Collection<String> userGroups = Collections.emptySet(); + private Collection<String> userRoles = Collections.emptySet(); + private Collection<String> tagNames = Collections.emptySet(); + private boolean result; + + public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine) { + this(accessRequest, scriptEngine, true); + } + + public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine, boolean enableJsonCtx) { + this.accessRequest = accessRequest.getReadOnlyCopy(); + this.scriptEngine = scriptEngine; + this.bindings = scriptEngine.createBindings(); + + RangerTagForEval currentTag = this.getCurrentTag(); + Map<String, String> tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap(); + + bindings.put(SCRIPT_VAR_ctx, this); + bindings.put(SCRIPT_VAR_tag, currentTag); + bindings.put(SCRIPT_VAR_tagAttr, tagAttribs); + + String preExecScript = ""; + + if (enableJsonCtx) { + bindings.put(SCRIPT_VAR__CTX_JSON, this.toJson()); + + preExecScript += SCRIPT_PREEXEC; + } + + if (StringUtils.isNotBlank(preExecScript)) { + try { + scriptEngine.eval(preExecScript, bindings); + } catch (ScriptException excp) { + LOG.error("RangerRequestScriptEvaluator(): initialization failed", excp); + } + } + } + + public static boolean needsJsonCtxEnabled(String script) { + boolean ret = false; + + if (script != null) { + Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script); + + ret = matcher.find(); + } + + return ret; + } + + public static boolean hasUserAttributeReference(String script) { + boolean ret = false; - return ret; - } - - public static String expandMacros(String script) { - return MACRO_PROCESSOR.expandMacros(script); - } - - public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine) { - this(accessRequest, scriptEngine, true); - } + if (script != null) { + Matcher matcher = USER_ATTRIBUTES_PATTERN.matcher(script); - public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine, boolean enableJsonCtx) { - this.accessRequest = accessRequest.getReadOnlyCopy(); - this.scriptEngine = scriptEngine; - this.bindings = scriptEngine.createBindings(); + ret = matcher.find(); + } - RangerTagForEval currentTag = this.getCurrentTag(); - Map<String, String> tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap(); + return ret; + } - bindings.put(SCRIPT_VAR_ctx, this); - bindings.put(SCRIPT_VAR_tag, currentTag); - bindings.put(SCRIPT_VAR_tagAttr, tagAttribs); - - String preExecScript = ""; + public static boolean hasGroupAttributeReference(String script) { + boolean ret = false; - if (enableJsonCtx) { - bindings.put(SCRIPT_VAR__CTX_JSON, this.toJson()); + if (script != null) { + Matcher matcher = GROUP_ATTRIBUTES_PATTERN.matcher(script); - preExecScript += SCRIPT_PREEXEC; - } + ret = matcher.find(); + } - if (StringUtils.isNotBlank(preExecScript)) { - try { - scriptEngine.eval(preExecScript, bindings); - } catch (ScriptException excp) { - LOG.error("RangerRequestScriptEvaluator(): initialization failed", excp); - } - } - } + return ret; + } - public Object evaluateScript(String script) { - script = expandMacros(script); + public static boolean hasUserGroupAttributeReference(String script) { + return hasUserAttributeReference(script) || hasGroupAttributeReference(script); + } - return evaluateScriptImpl(script); - } + public static boolean hasUserGroupAttributeReference(Collection<String> scripts) { + boolean ret = false; - public Object evaluateConditionScript(String script) { - Object ret = evaluateScript(script); + if (scripts != null) { + for (String script : scripts) { + if (hasUserGroupAttributeReference(script)) { + ret = true; - if (ret == null) { - ret = getResult(); - } + break; + } + } + } - if (ret instanceof Boolean) { - result = (Boolean) ret; - } + return ret; + } - return ret; - } + public static String expandMacros(String script) { + return MACRO_PROCESSOR.expandMacros(script); + } - private Object evaluateScriptImpl(String script) { - Object ret = null; - RangerPerfTracer perf = null; + public static void init(Configuration config) { + StringBuilder sb = new StringBuilder(DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT); - try { - if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_EVAL)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_EVAL, "RangerRequestScriptEvaluator.evaluateScript(requestHash=" + accessRequest.hashCode() + ")"); - } + sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME); - String preExec = SCRIPT_SAFE_PREEXEC; + String additionalDateFormatsValue = config != null ? config.get(TAG_ATTR_DATE_FORMAT_PROP) : null; - if (script.contains(".includes(")) { - preExec += SCRIPT_POLYFILL_INCLUDES; - } + if (StringUtils.isNotBlank(additionalDateFormatsValue)) { + sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(additionalDateFormatsValue); + } - if (script.contains(".intersects(")) { - preExec += SCRIPT_POLYFILL_INTERSECTS; - } + String[] formatStrings = sb.toString().split(TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX); - if (JavaScriptEdits.hasDoubleBrackets(script)) { - script = JavaScriptEdits.replaceDoubleBrackets(script); - } + Arrays.sort(formatStrings, (first, second) -> Integer.compare(second.length(), first.length())); - ret = scriptEngine.eval(preExec + script, bindings); - } catch (NullPointerException nullp) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): eval called with NULL argument(s)", nullp); - } catch (ScriptException excp) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): failed to evaluate script", excp); - } catch (Throwable t) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): failed to evaluate script", t); - } finally { - RangerPerfTracer.log(perf); - } + RangerRequestScriptEvaluator.dateFormatStrings = formatStrings; + } - return ret; - } + public Object evaluateScript(String script) { + script = expandMacros(script); - private String toJson() { - RangerPerfTracer perf = null; + return evaluateScriptImpl(script); + } - if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_TOJSON)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_TOJSON, "RangerRequestScriptEvaluator.toJson(requestHash=" + accessRequest.hashCode() + ")"); - } + public Object evaluateConditionScript(String script) { + Object ret = evaluateScript(script); - Map<String, Object> ret = new HashMap<>(); - Map<String, Object> request = new HashMap<>(); - Date accessTime = accessRequest.getAccessTime(); + if (ret == null) { + ret = getResult(); + } - init(); + if (ret instanceof Boolean) { + result = (Boolean) ret; + } - if (accessTime != null) { - request.put(SCRIPT_FIELD_ACCESS_TIME, accessTime.getTime()); - } + return ret; + } - request.put(SCRIPT_FIELD_ACCESS_TYPE, accessRequest.getAccessType()); - request.put(SCRIPT_FIELD_ACTION, accessRequest.getAction()); - request.put(SCRIPT_FIELD_CLIENT_IP_ADDRESS, accessRequest.getClientIPAddress()); - request.put(SCRIPT_FIELD_CLIENT_TYPE, accessRequest.getClientType()); - request.put(SCRIPT_FIELD_CLUSTER_NAME, accessRequest.getClusterName()); - request.put(SCRIPT_FIELD_CLUSTER_TYPE, accessRequest.getClusterType()); - request.put(SCRIPT_FIELD_FORWARDED_ADDRESSES, accessRequest.getForwardedAddresses()); - request.put(SCRIPT_FIELD_REMOTE_IP_ADDRESS, accessRequest.getRemoteIPAddress()); - request.put(SCRIPT_FIELD_REQUEST_DATA, accessRequest.getRequestData()); + public String getResource() { + String ret = null; + RangerAccessResource val = RangerAccessRequestUtil.getCurrentResourceFromContext(getRequestContext()); - if (accessRequest.getResource() != null) { - Map<String, Object> resource = new HashMap<>(accessRequest.getResource().getAsMap()); + if (val != null) { + ret = val.getAsString(); + } - resource.put(SCRIPT_FIELD__OWNER_USER, accessRequest.getResource().getOwnerUser()); + return ret; + } - request.put(SCRIPT_FIELD_RESOURCE, resource); - } + public String getResourceZone() { + String ret = RangerAccessRequestUtil.getResourceZoneNameFromContext(getRequestContext()); - request.put(SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE, accessRequest.getResourceMatchingScope()); + return ret != null ? ret : StringUtils.EMPTY; + } - request.put(SCRIPT_FIELD_USER, getUser()); - request.put(SCRIPT_FIELD_USER_GROUPS, userGroups); - request.put(SCRIPT_FIELD_USER_ROLES, userRoles); + public Set<String> getResourceZones() { + Set<String> ret = RangerAccessRequestUtil.getResourceZoneNamesFromContext(getRequestContext()); - request.put(SCRIPT_FIELD_USER_ATTRIBUTES, userAttrs); + return ret != null ? Collections.emptySet() : ret; + } - request.put(SCRIPT_FIELD_USER_GROUP_ATTRIBUTES, groupAttrs); - request.put(SCRIPT_FIELD_UGA, new UserGroupsAttributes(userGroups, groupAttrs).getAttributes()); + public String getRequestContextAttribute(String attributeName) { + String ret = null; - ret.put(SCRIPT_FIELD_REQUEST, request); + if (StringUtils.isNotBlank(attributeName)) { + Object val = getRequestContext().get(attributeName); - ret.put(SCRIPT_FIELD_TAGS, tags); - ret.put(SCRIPT_FIELD_TAG_NAMES, tagNames); - ret.put(SCRIPT_FIELD_TAG, tag); + if (val != null) { + ret = val.toString(); + } + } - String strRet = JsonUtils.objectToJson(ret); + return ret; + } - RangerPerfTracer.log(perf); + public boolean isAccessTypeAny() { + return accessRequest.isAccessTypeAny(); + } - return strRet; - } + public boolean isAccessTypeDelegatedAdmin() { + return accessRequest.isAccessTypeDelegatedAdmin(); + } - public static void init(Configuration config) { - StringBuilder sb = new StringBuilder(DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT); + public String getUser() { + return accessRequest.getUser(); + } - sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME); + public Set<String> getUserGroups() { + return accessRequest.getUserGroups(); + } - String additionalDateFormatsValue = config != null ? config.get(TAG_ATTR_DATE_FORMAT_PROP) : null; + public Set<String> getUserRoles() { + return RangerAccessRequestUtil.getUserRoles(accessRequest); + } + + public Date getAccessTime() { + return accessRequest.getAccessTime() != null ? accessRequest.getAccessTime() : new Date(); + } + + public String getClientIPAddress() { + return accessRequest.getClientIPAddress(); + } + + public String getClientType() { + return accessRequest.getClientType(); + } + + public String getAction() { + return accessRequest.getAction(); + } + + public String getRequestData() { + return accessRequest.getRequestData(); + } + + public String getSessionId() { + return accessRequest.getSessionId(); + } + + public RangerTagForEval getCurrentTag() { + RangerTagForEval ret = RangerAccessRequestUtil.getCurrentTagFromContext(getRequestContext()); + + if (ret == null) { + if (LOG.isDebugEnabled()) { Review Comment: nit: isDebugEnabled() can be removed. ########## agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngineForDeltas.java: ########## @@ -289,119 +290,117 @@ private void runTests(InputStreamReader reader, String testName) { policyEngine.setUseForwardedIPAddress(useForwardedIPAddress); policyEngine.setTrustedProxyAddresses(trustedProxyAddresses); - PolicyEngineTestCase.TestsInfo testsInfo = testCase.testsInfo; - do { - runTestCaseTests(policyEngine, testCase.serviceDef, testName, testsInfo.tests); - if (testsInfo.updatedPolicies != null && CollectionUtils.isNotEmpty(testsInfo.updatedPolicies.policyDeltas)) { - servicePolicies.setPolicyDeltas(testsInfo.updatedPolicies.policyDeltas); - servicePolicies.setPolicies(null); - if (MapUtils.isNotEmpty(testsInfo.updatedPolicies.securityZones)) { - servicePolicies.setSecurityZones(testsInfo.updatedPolicies.securityZones); - } - policyEngine = (RangerPolicyEngineImpl) RangerPolicyEngineImpl.getPolicyEngine(policyEngine, servicePolicies); - - testsInfo = null; - } else { - testsInfo = null; - } - - } while (testsInfo != null && testsInfo.tests != null); - - } + PolicyEngineTestCase.TestsInfo testsInfo = testCase.testsInfo; + do { + runTestCaseTests(policyEngine, testCase.serviceDef, testName, testsInfo.tests); + if (testsInfo.updatedPolicies != null && CollectionUtils.isNotEmpty(testsInfo.updatedPolicies.policyDeltas)) { + servicePolicies.setPolicyDeltas(testsInfo.updatedPolicies.policyDeltas); + servicePolicies.setPolicies(null); + if (MapUtils.isNotEmpty(testsInfo.updatedPolicies.securityZones)) { + servicePolicies.setSecurityZones(testsInfo.updatedPolicies.securityZones); + } + policyEngine = (RangerPolicyEngineImpl) RangerPolicyEngineImpl.getPolicyEngine(policyEngine, servicePolicies); + + testsInfo = null; + } else { + testsInfo = null; + } + } + while (testsInfo != null && testsInfo.tests != null); + } private void runTestCaseTests(RangerPolicyEngine policyEngine, RangerServiceDef serviceDef, String testName, List<TestData> tests) { RangerAccessRequest request; - for(TestData test : tests) { - request = test.request; - - if (request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_TAGS) || - request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) { - // Create a new AccessRequest - RangerAccessRequestImpl newRequest = - new RangerAccessRequestImpl(request.getResource(), request.getAccessType(), - request.getUser(), request.getUserGroups(), null); - - newRequest.setClientType(request.getClientType()); - newRequest.setAccessTime(request.getAccessTime()); - newRequest.setAction(request.getAction()); - newRequest.setRemoteIPAddress(request.getRemoteIPAddress()); - newRequest.setForwardedAddresses(request.getForwardedAddresses()); - newRequest.setRequestData(request.getRequestData()); - newRequest.setSessionId(request.getSessionId()); - - Map<String, Object> context = request.getContext(); - String tagsJsonString = (String) context.get(RangerAccessRequestUtil.KEY_CONTEXT_TAGS); - context.remove(RangerAccessRequestUtil.KEY_CONTEXT_TAGS); - - if(!StringUtils.isEmpty(tagsJsonString)) { - try { - Type setType = new TypeToken<Set<RangerTagForEval>>() { - }.getType(); - Set<RangerTagForEval> tags = gsonBuilder.fromJson(tagsJsonString, setType); - - context.put(RangerAccessRequestUtil.KEY_CONTEXT_TAGS, tags); - } catch (Exception e) { - System.err.println("TestPolicyEngineForDeltas.runTests(): error parsing TAGS JSON string in file " + testName + ", tagsJsonString=" + - tagsJsonString + ", exception=" + e); - } - } else if (request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) { - String resourcesJsonString = (String) context.get(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES); - context.remove(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES); - if (!StringUtils.isEmpty(resourcesJsonString)) { - try { - /* - Reader stringReader = new StringReader(resourcesJsonString); - RangerRequestedResources resources = gsonBuilder.fromJson(stringReader, RangerRequestedResources.class); - */ - - Type myType = new TypeToken<RangerRequestedResources>() { - }.getType(); - RangerRequestedResources resources = gsonBuilder.fromJson(resourcesJsonString, myType); - - context.put(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES, resources); - } catch (Exception e) { - System.err.println("TestPolicyEngineForDeltas.runTests(): error parsing REQUESTED_RESOURCES string in file " + testName + ", resourcesJsonString=" + - resourcesJsonString + ", exception=" + e); - } - } - } - newRequest.setContext(context); - - // accessResource.ServiceDef is set here, so that we can skip call to policyEngine.preProcess() which - // sets the serviceDef in the resource AND calls enrichers. We dont want enrichers to be called when - // context already contains tags -- This may change when we want enrichers to enrich request in the - // presence of tags!!! - - // Safe cast - RangerAccessResourceImpl accessResource = (RangerAccessResourceImpl) request.getResource(); - accessResource.setServiceDef(serviceDef); - - request = newRequest; - - } - - RangerAccessResultProcessor auditHandler = new RangerDefaultAuditHandler(); - - if(test.result != null) { + for (TestData test : tests) { + request = test.request; + + if (request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_TAGS) || + request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) { + // Create a new AccessRequest + RangerAccessRequestImpl newRequest = Review Comment: single line may be used here. ########## agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java: ########## @@ -25,1375 +25,1481 @@ import org.apache.ranger.authorization.utils.JsonUtils; import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.contextenricher.RangerTagForEval; +import org.apache.ranger.plugin.util.JavaScriptEdits; import org.apache.ranger.plugin.util.MacroProcessor; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.RangerPerfTracer; import org.apache.ranger.plugin.util.RangerTimeRangeChecker; import org.apache.ranger.plugin.util.RangerUserStore; -import org.apache.ranger.plugin.util.JavaScriptEdits; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptException; + import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +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.Objects; +import java.util.Set; +import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.apache.ranger.plugin.util.RangerCommonConstants.*; - +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACCESS_TIME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACCESS_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_ACTION; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLIENT_IP_ADDRESS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLIENT_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLUSTER_NAME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_CLUSTER_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_FORWARDED_ADDRESSES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REMOTE_IP_ADDRESS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REQUEST; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_REQUEST_DATA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_RESOURCE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAGS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_TAG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_UGA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_ATTRIBUTES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_GROUPS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_GROUP_ATTRIBUTES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD_USER_ROLES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__MATCH_TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__NAME; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__OWNER_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_FIELD__TYPE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_ATTR_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_TAG_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_ATTR_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UG_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_UR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_NAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_NAMES_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_GET_USER_ATTR_Q; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_ANY_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_NO_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_TAG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_UG_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_HAS_USER_ATTR; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_AFTER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_BEFORE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_ACCESS_TIME_BETWEEN; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ANY_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ANY_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_IN_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_NOT_IN_ANY_GROUP; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_IS_NOT_IN_ANY_ROLE; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_TAG_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UG_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_UR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_USER_ATTR_NAMES_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_MACRO_USER_ATTR_NAMES_Q_CSV; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_POLYFILL_INCLUDES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_POLYFILL_INTERSECTS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_REQ; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_RES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAGNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_TAGS; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UG; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UGA; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_UGNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_URNAMES; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_USER; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR__CTX; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR__CTX_JSON; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_ctx; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_tag; +import static org.apache.ranger.plugin.util.RangerCommonConstants.SCRIPT_VAR_tagAttr; public final class RangerRequestScriptEvaluator { - private static final Logger LOG = LoggerFactory.getLogger(RangerRequestScriptEvaluator.class); - - private static final Logger PERF_POLICY_CONDITION_SCRIPT_TOJSON = RangerPerfTracer.getPerfLogger("policy.condition.script.tojson"); - private static final Logger PERF_POLICY_CONDITION_SCRIPT_EVAL = RangerPerfTracer.getPerfLogger("policy.condition.script.eval"); - private static final String TAG_ATTR_DATE_FORMAT_PROP = "ranger.plugin.tag.attr.additional.date.formats"; - private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR = "||"; - private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX = "\\|\\|"; - private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy/MM/dd"; - private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME = "ATLAS_DATE_FORMAT"; - private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; - private static final String SCRIPT_SAFE_PREEXEC = "exit=null;quit=null;"; - private static final String SCRIPT_PREEXEC = SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + "); J=JSON.stringify;" + - SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" + - SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" + - SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" + - SCRIPT_VAR_UGNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" + - SCRIPT_VAR_UG + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" + - SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" + - SCRIPT_VAR_URNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" + - SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" + - SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" + - SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";"; - private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern()); - private static final Pattern USER_ATTRIBUTES_PATTERN = Pattern.compile(getUserAttributesPattern()); - private static final Pattern GROUP_ATTRIBUTES_PATTERN = Pattern.compile(getGroupAttributesPattern()); - private static final String STR_QUOTE = "'"; - private static final String STR_COMMA = ","; - - private static final MacroProcessor MACRO_PROCESSOR = new MacroProcessor(getMacrosMap()); - - private static String[] dateFormatStrings = null; - - private final RangerAccessRequest accessRequest; - private final ScriptEngine scriptEngine; - private final Bindings bindings; - private boolean initDone = false; - private Map<String, String> userAttrs = Collections.emptyMap(); - private Map<String, Map<String, String>> groupAttrs = Collections.emptyMap(); - private Map<String, Map<String, Object>> tags = Collections.emptyMap(); - private Map<String, Object> tag = Collections.emptyMap(); - private Collection<String> userGroups = Collections.emptySet(); - private Collection<String> userRoles = Collections.emptySet(); - private Collection<String> tagNames = Collections.emptySet(); - private Boolean result = false; - - static { - init(null); - } - - private static final ThreadLocal<List<SimpleDateFormat>> THREADLOCAL_DATE_FORMATS = - new ThreadLocal<List<SimpleDateFormat>>() { - @Override protected List<SimpleDateFormat> initialValue() { - List<SimpleDateFormat> ret = new ArrayList<>(); - - for (String dateFormatString : dateFormatStrings) { - try { - if (StringUtils.isNotBlank(dateFormatString)) { - if (StringUtils.equalsIgnoreCase(dateFormatString, DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME)) { - dateFormatString = DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT; - } - SimpleDateFormat df = new SimpleDateFormat(dateFormatString); - df.setLenient(false); - ret.add(df); - } - } catch (Exception exception) { - // Ignore - } - } - - return ret; - } - }; - - - public static boolean needsJsonCtxEnabled(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasUserAttributeReference(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = USER_ATTRIBUTES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasGroupAttributeReference(String script) { - boolean ret = false; - - if (script != null) { - Matcher matcher = GROUP_ATTRIBUTES_PATTERN.matcher(script); - - ret = matcher.find(); - } - - return ret; - } - - public static boolean hasUserGroupAttributeReference(String script) { - return hasUserAttributeReference(script) || hasGroupAttributeReference(script); - } - - public static boolean hasUserGroupAttributeReference(Collection<String> scripts) { - boolean ret = false; - - if (scripts != null) { - for (String script : scripts) { - if (hasUserGroupAttributeReference(script)) { - ret = true; - - break; - } - } - } + private static final Logger LOG = LoggerFactory.getLogger(RangerRequestScriptEvaluator.class); + + private static final Logger PERF_POLICY_CONDITION_SCRIPT_TOJSON = RangerPerfTracer.getPerfLogger("policy.condition.script.tojson"); + private static final Logger PERF_POLICY_CONDITION_SCRIPT_EVAL = RangerPerfTracer.getPerfLogger("policy.condition.script.eval"); + private static final String TAG_ATTR_DATE_FORMAT_PROP = "ranger.plugin.tag.attr.additional.date.formats"; + private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR = "||"; + private static final String TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX = "\\|\\|"; + private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy/MM/dd"; + private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME = "ATLAS_DATE_FORMAT"; + private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static final String SCRIPT_SAFE_PREEXEC = "exit=null;quit=null;"; + private static final String SCRIPT_PREEXEC = SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + "); J=JSON.stringify;" + + SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" + + SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" + + SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" + + SCRIPT_VAR_UGNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" + + SCRIPT_VAR_UG + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" + + SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" + + SCRIPT_VAR_URNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" + + SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" + + SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" + + SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";"; + private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern()); + private static final Pattern USER_ATTRIBUTES_PATTERN = Pattern.compile(getUserAttributesPattern()); + private static final Pattern GROUP_ATTRIBUTES_PATTERN = Pattern.compile(getGroupAttributesPattern()); + private static final String STR_QUOTE = "'"; + private static final String STR_COMMA = ","; + + private static final MacroProcessor MACRO_PROCESSOR = new MacroProcessor(getMacrosMap()); + + private static String[] dateFormatStrings = {}; + private static final ThreadLocal<List<SimpleDateFormat>> THREADLOCAL_DATE_FORMATS = ThreadLocal.withInitial(() -> { + List<SimpleDateFormat> ret = new ArrayList<>(); + + for (String dateFormatString : dateFormatStrings) { + try { + if (StringUtils.isNotBlank(dateFormatString)) { + if (StringUtils.equalsIgnoreCase(dateFormatString, DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME)) { + dateFormatString = DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT; + } + SimpleDateFormat df = new SimpleDateFormat(dateFormatString); + df.setLenient(false); + ret.add(df); + } + } catch (Exception exception) { + // Ignore + } + } + + return ret; + }); + + private final RangerAccessRequest accessRequest; + private final ScriptEngine scriptEngine; + private final Bindings bindings; + private boolean initDone; + private Map<String, String> userAttrs = Collections.emptyMap(); + private Map<String, Map<String, String>> groupAttrs = Collections.emptyMap(); + private Map<String, Map<String, Object>> tags = Collections.emptyMap(); + private Map<String, Object> tag = Collections.emptyMap(); + private Collection<String> userGroups = Collections.emptySet(); + private Collection<String> userRoles = Collections.emptySet(); + private Collection<String> tagNames = Collections.emptySet(); + private boolean result; + + public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine) { + this(accessRequest, scriptEngine, true); + } + + public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine, boolean enableJsonCtx) { + this.accessRequest = accessRequest.getReadOnlyCopy(); + this.scriptEngine = scriptEngine; + this.bindings = scriptEngine.createBindings(); + + RangerTagForEval currentTag = this.getCurrentTag(); + Map<String, String> tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap(); + + bindings.put(SCRIPT_VAR_ctx, this); + bindings.put(SCRIPT_VAR_tag, currentTag); + bindings.put(SCRIPT_VAR_tagAttr, tagAttribs); + + String preExecScript = ""; + + if (enableJsonCtx) { + bindings.put(SCRIPT_VAR__CTX_JSON, this.toJson()); + + preExecScript += SCRIPT_PREEXEC; + } + + if (StringUtils.isNotBlank(preExecScript)) { + try { + scriptEngine.eval(preExecScript, bindings); + } catch (ScriptException excp) { + LOG.error("RangerRequestScriptEvaluator(): initialization failed", excp); + } + } + } + + public static boolean needsJsonCtxEnabled(String script) { + boolean ret = false; + + if (script != null) { + Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script); + + ret = matcher.find(); + } + + return ret; + } + + public static boolean hasUserAttributeReference(String script) { + boolean ret = false; - return ret; - } - - public static String expandMacros(String script) { - return MACRO_PROCESSOR.expandMacros(script); - } - - public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine) { - this(accessRequest, scriptEngine, true); - } + if (script != null) { + Matcher matcher = USER_ATTRIBUTES_PATTERN.matcher(script); - public RangerRequestScriptEvaluator(RangerAccessRequest accessRequest, ScriptEngine scriptEngine, boolean enableJsonCtx) { - this.accessRequest = accessRequest.getReadOnlyCopy(); - this.scriptEngine = scriptEngine; - this.bindings = scriptEngine.createBindings(); + ret = matcher.find(); + } - RangerTagForEval currentTag = this.getCurrentTag(); - Map<String, String> tagAttribs = currentTag != null ? currentTag.getAttributes() : Collections.emptyMap(); + return ret; + } - bindings.put(SCRIPT_VAR_ctx, this); - bindings.put(SCRIPT_VAR_tag, currentTag); - bindings.put(SCRIPT_VAR_tagAttr, tagAttribs); - - String preExecScript = ""; + public static boolean hasGroupAttributeReference(String script) { + boolean ret = false; - if (enableJsonCtx) { - bindings.put(SCRIPT_VAR__CTX_JSON, this.toJson()); + if (script != null) { + Matcher matcher = GROUP_ATTRIBUTES_PATTERN.matcher(script); - preExecScript += SCRIPT_PREEXEC; - } + ret = matcher.find(); + } - if (StringUtils.isNotBlank(preExecScript)) { - try { - scriptEngine.eval(preExecScript, bindings); - } catch (ScriptException excp) { - LOG.error("RangerRequestScriptEvaluator(): initialization failed", excp); - } - } - } + return ret; + } - public Object evaluateScript(String script) { - script = expandMacros(script); + public static boolean hasUserGroupAttributeReference(String script) { + return hasUserAttributeReference(script) || hasGroupAttributeReference(script); + } - return evaluateScriptImpl(script); - } + public static boolean hasUserGroupAttributeReference(Collection<String> scripts) { + boolean ret = false; - public Object evaluateConditionScript(String script) { - Object ret = evaluateScript(script); + if (scripts != null) { + for (String script : scripts) { + if (hasUserGroupAttributeReference(script)) { + ret = true; - if (ret == null) { - ret = getResult(); - } + break; + } + } + } - if (ret instanceof Boolean) { - result = (Boolean) ret; - } + return ret; + } - return ret; - } + public static String expandMacros(String script) { + return MACRO_PROCESSOR.expandMacros(script); + } - private Object evaluateScriptImpl(String script) { - Object ret = null; - RangerPerfTracer perf = null; + public static void init(Configuration config) { + StringBuilder sb = new StringBuilder(DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT); - try { - if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_EVAL)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_EVAL, "RangerRequestScriptEvaluator.evaluateScript(requestHash=" + accessRequest.hashCode() + ")"); - } + sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME); - String preExec = SCRIPT_SAFE_PREEXEC; + String additionalDateFormatsValue = config != null ? config.get(TAG_ATTR_DATE_FORMAT_PROP) : null; - if (script.contains(".includes(")) { - preExec += SCRIPT_POLYFILL_INCLUDES; - } + if (StringUtils.isNotBlank(additionalDateFormatsValue)) { + sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(additionalDateFormatsValue); + } - if (script.contains(".intersects(")) { - preExec += SCRIPT_POLYFILL_INTERSECTS; - } + String[] formatStrings = sb.toString().split(TAG_ATTR_DATE_FORMAT_SEPARATOR_REGEX); - if (JavaScriptEdits.hasDoubleBrackets(script)) { - script = JavaScriptEdits.replaceDoubleBrackets(script); - } + Arrays.sort(formatStrings, (first, second) -> Integer.compare(second.length(), first.length())); - ret = scriptEngine.eval(preExec + script, bindings); - } catch (NullPointerException nullp) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): eval called with NULL argument(s)", nullp); - } catch (ScriptException excp) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): failed to evaluate script", excp); - } catch (Throwable t) { - LOG.error("RangerRequestScriptEvaluator.evaluateScript(): failed to evaluate script", t); - } finally { - RangerPerfTracer.log(perf); - } + RangerRequestScriptEvaluator.dateFormatStrings = formatStrings; + } - return ret; - } + public Object evaluateScript(String script) { + script = expandMacros(script); - private String toJson() { - RangerPerfTracer perf = null; + return evaluateScriptImpl(script); + } - if (RangerPerfTracer.isPerfTraceEnabled(PERF_POLICY_CONDITION_SCRIPT_TOJSON)) { - perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_CONDITION_SCRIPT_TOJSON, "RangerRequestScriptEvaluator.toJson(requestHash=" + accessRequest.hashCode() + ")"); - } + public Object evaluateConditionScript(String script) { + Object ret = evaluateScript(script); - Map<String, Object> ret = new HashMap<>(); - Map<String, Object> request = new HashMap<>(); - Date accessTime = accessRequest.getAccessTime(); + if (ret == null) { + ret = getResult(); + } - init(); + if (ret instanceof Boolean) { + result = (Boolean) ret; + } - if (accessTime != null) { - request.put(SCRIPT_FIELD_ACCESS_TIME, accessTime.getTime()); - } + return ret; + } - request.put(SCRIPT_FIELD_ACCESS_TYPE, accessRequest.getAccessType()); - request.put(SCRIPT_FIELD_ACTION, accessRequest.getAction()); - request.put(SCRIPT_FIELD_CLIENT_IP_ADDRESS, accessRequest.getClientIPAddress()); - request.put(SCRIPT_FIELD_CLIENT_TYPE, accessRequest.getClientType()); - request.put(SCRIPT_FIELD_CLUSTER_NAME, accessRequest.getClusterName()); - request.put(SCRIPT_FIELD_CLUSTER_TYPE, accessRequest.getClusterType()); - request.put(SCRIPT_FIELD_FORWARDED_ADDRESSES, accessRequest.getForwardedAddresses()); - request.put(SCRIPT_FIELD_REMOTE_IP_ADDRESS, accessRequest.getRemoteIPAddress()); - request.put(SCRIPT_FIELD_REQUEST_DATA, accessRequest.getRequestData()); + public String getResource() { + String ret = null; + RangerAccessResource val = RangerAccessRequestUtil.getCurrentResourceFromContext(getRequestContext()); - if (accessRequest.getResource() != null) { - Map<String, Object> resource = new HashMap<>(accessRequest.getResource().getAsMap()); + if (val != null) { + ret = val.getAsString(); + } - resource.put(SCRIPT_FIELD__OWNER_USER, accessRequest.getResource().getOwnerUser()); + return ret; + } - request.put(SCRIPT_FIELD_RESOURCE, resource); - } + public String getResourceZone() { + String ret = RangerAccessRequestUtil.getResourceZoneNameFromContext(getRequestContext()); - request.put(SCRIPT_FIELD_RESOURCE_MATCHING_SCOPE, accessRequest.getResourceMatchingScope()); + return ret != null ? ret : StringUtils.EMPTY; + } - request.put(SCRIPT_FIELD_USER, getUser()); - request.put(SCRIPT_FIELD_USER_GROUPS, userGroups); - request.put(SCRIPT_FIELD_USER_ROLES, userRoles); + public Set<String> getResourceZones() { + Set<String> ret = RangerAccessRequestUtil.getResourceZoneNamesFromContext(getRequestContext()); - request.put(SCRIPT_FIELD_USER_ATTRIBUTES, userAttrs); + return ret != null ? Collections.emptySet() : ret; + } - request.put(SCRIPT_FIELD_USER_GROUP_ATTRIBUTES, groupAttrs); - request.put(SCRIPT_FIELD_UGA, new UserGroupsAttributes(userGroups, groupAttrs).getAttributes()); + public String getRequestContextAttribute(String attributeName) { + String ret = null; - ret.put(SCRIPT_FIELD_REQUEST, request); + if (StringUtils.isNotBlank(attributeName)) { + Object val = getRequestContext().get(attributeName); - ret.put(SCRIPT_FIELD_TAGS, tags); - ret.put(SCRIPT_FIELD_TAG_NAMES, tagNames); - ret.put(SCRIPT_FIELD_TAG, tag); + if (val != null) { + ret = val.toString(); + } + } - String strRet = JsonUtils.objectToJson(ret); + return ret; + } - RangerPerfTracer.log(perf); + public boolean isAccessTypeAny() { + return accessRequest.isAccessTypeAny(); + } - return strRet; - } + public boolean isAccessTypeDelegatedAdmin() { + return accessRequest.isAccessTypeDelegatedAdmin(); + } - public static void init(Configuration config) { - StringBuilder sb = new StringBuilder(DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT); + public String getUser() { + return accessRequest.getUser(); + } - sb.append(TAG_ATTR_DATE_FORMAT_SEPARATOR).append(DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME); + public Set<String> getUserGroups() { + return accessRequest.getUserGroups(); + } - String additionalDateFormatsValue = config != null ? config.get(TAG_ATTR_DATE_FORMAT_PROP) : null; + public Set<String> getUserRoles() { + return RangerAccessRequestUtil.getUserRoles(accessRequest); + } + + public Date getAccessTime() { + return accessRequest.getAccessTime() != null ? accessRequest.getAccessTime() : new Date(); + } + + public String getClientIPAddress() { + return accessRequest.getClientIPAddress(); + } + + public String getClientType() { + return accessRequest.getClientType(); + } + + public String getAction() { + return accessRequest.getAction(); + } + + public String getRequestData() { + return accessRequest.getRequestData(); + } + + public String getSessionId() { + return accessRequest.getSessionId(); + } + + public RangerTagForEval getCurrentTag() { + RangerTagForEval ret = RangerAccessRequestUtil.getCurrentTagFromContext(getRequestContext()); + + if (ret == null) { + if (LOG.isDebugEnabled()) { + logDebug("RangerRequestScriptEvaluator.getCurrentTag() - No current TAG object. Script execution must be for resource-based policy."); + } + } + return ret; + } + + public String getCurrentTagType() { + RangerTagForEval tagObject = getCurrentTag(); + return (tagObject != null) ? tagObject.getType() : null; + } + + public Set<String> getAllTagTypes() { + Set<String> allTagTypes = null; + Set<RangerTagForEval> tagObjectList = getAllTags(); + + if (CollectionUtils.isNotEmpty(tagObjectList)) { + for (RangerTagForEval tag : tagObjectList) { + String tagType = tag.getType(); + if (allTagTypes == null) { + allTagTypes = new HashSet<>(); + } + allTagTypes.add(tagType); + } + } + + return allTagTypes; + } + + public Map<String, String> getTagAttributes(final String tagType) { + Map<String, String> ret = null; + + if (StringUtils.isNotBlank(tagType)) { + Set<RangerTagForEval> tagObjectList = getAllTags(); + + // Assumption: There is exactly one tag with given tagType in the list of tags - may not be true ***TODO*** + // This will get attributes of the first tagType that matches + if (CollectionUtils.isNotEmpty(tagObjectList)) { + for (RangerTagForEval tag : tagObjectList) { + if (tag.getType().equals(tagType)) { + ret = tag.getAttributes(); + break; + } + } + } + } + + return ret; + } + + public List<Map<String, String>> getTagAttributesForAllMatchingTags(final String tagType) { + List<Map<String, String>> ret = null; + + if (StringUtils.isNotBlank(tagType)) { + Set<RangerTagForEval> tagObjectList = getAllTags(); + + // Assumption: There is exactly one tag with given tagType in the list of tags - may not be true ***TODO*** + // This will get attributes of the first tagType that matches + if (CollectionUtils.isNotEmpty(tagObjectList)) { + for (RangerTagForEval tag : tagObjectList) { + if (tag.getType().equals(tagType)) { + Map<String, String> tagAttributes = tag.getAttributes(); + if (tagAttributes != null) { + if (ret == null) { + ret = new ArrayList<>(); + } + ret.add(tagAttributes); + } + break; + } + } + } + } + + return ret; + } + + public Set<String> getAttributeNames(final String tagType) { + Set<String> ret = null; + Map<String, String> attributes = getTagAttributes(tagType); + + if (attributes != null) { + ret = attributes.keySet(); + } + + return ret; + } + + public String getAttributeValue(final String tagType, final String attributeName) { + String ret = null; + + if (StringUtils.isNotBlank(tagType) || StringUtils.isNotBlank(attributeName)) { + Map<String, String> attributes = getTagAttributes(tagType); + + if (attributes != null) { + ret = attributes.get(attributeName); + } + } + return ret; + } + + public List<String> getAttributeValueForAllMatchingTags(final String tagType, final String attributeName) { + List<String> ret = null; + + if (StringUtils.isNotBlank(tagType) || StringUtils.isNotBlank(attributeName)) { + Map<String, String> attributes = getTagAttributes(tagType); + + if (attributes != null && attributes.get(attributeName) != null) { + if (ret == null) { + ret = new ArrayList<>(); + } + ret.add(attributes.get(attributeName)); + } + } + return ret; + } + + public String getAttributeValue(final String attributeName) { + String ret = null; + + if (StringUtils.isNotBlank(attributeName)) { + RangerTagForEval tag = getCurrentTag(); + Map<String, String> attributes = null; + if (tag != null) { + attributes = tag.getAttributes(); + } + if (attributes != null) { + ret = attributes.get(attributeName); + } + } + + return ret; + } + + public boolean getResult() { + return result; + } + + public void setResult(final boolean result) { + this.result = result; + } + + public Date getAsDate(String value) { + Date ret = null; + + if (StringUtils.isNotBlank(value)) { + for (SimpleDateFormat simpleDateFormat : THREADLOCAL_DATE_FORMATS.get()) { + ret = getAsDate(value, simpleDateFormat); + if (ret != null) { + if (LOG.isDebugEnabled()) { Review Comment: please check occurrences for isDebugEnabled in this file. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@ranger.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org