diff --git a/agents-common/pom.xml b/agents-common/pom.xml index 6b82eb49f5..bb2a87a192 100644 --- a/agents-common/pom.xml +++ b/agents-common/pom.xml @@ -160,6 +160,11 @@ ranger-audit-core ${project.version} + + org.apache.ranger + ranger-authz-api + ${project.version} + org.apache.ranger ranger-plugin-classloader diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java b/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java index 3132a75cd2..a9fb1863af 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/audit/RangerDefaultAuditHandler.java @@ -128,7 +128,7 @@ public AuthzAuditEvent getAuthzEvents(RangerAccessResult result) { ret.setClientIP(request.getClientIPAddress()); ret.setClientType(request.getClientType()); ret.setSessionId(request.getSessionId()); - ret.setAclEnforcer(moduleName); + ret.setAclEnforcer(RangerAccessRequestUtil.getAclEnforcerOrDefault(request.getContext(), moduleName)); Set tags = getTags(request); if (tags != null) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerInlinePolicy.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerInlinePolicy.java new file mode 100644 index 0000000000..d33eddbd3f --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerInlinePolicy.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ranger.plugin.model; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +@JsonIgnoreProperties(ignoreUnknown = true) +public class RangerInlinePolicy implements java.io.Serializable { + private static final long serialVersionUID = 1L; + + public enum Mode { + INLINE, // default: request must be allowed by this inline policy + RANGER_AND_INLINE, // request must be allowed by both Ranger policies and this inline policy + RANGER_OR_INLINE // request must be allowed by either Ranger policies or this inline policy + } + + private String grantor; // example: "r:role1"; when non-empty, request must be allowed for grantor principal as well + private Mode mode; + private List grants; + private String createdBy; + private long createTime; + + public RangerInlinePolicy() { + this.mode = Mode.INLINE; + } + + public RangerInlinePolicy(String grantor, Mode mode, List grants, String createdBy) { + this.grantor = grantor; + this.mode = mode; + this.grants = grants; + this.createdBy = createdBy; + this.createTime = System.currentTimeMillis(); + } + + public String getGrantor() { + return grantor; + } + + public void setGrantor(String grantor) { + this.grantor = grantor; + } + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public List getGrants() { + return grants; + } + + public void setGrants(List grants) { + this.grants = grants; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "RangerInlinePolicy{" + + "grantor=" + grantor + "," + + "mode=" + mode + "," + + "grants=" + grants + "," + + "createdBy=" + createdBy + "," + + "createTime=" + createTime + + "}"; + } + + public static class Grant { + private Set principals; // example: [ "u:user1, "g:group1", "r:role1" ]; if empty, means public grant + private Set resources; // example: [ "key:vol1/bucket1/db1/tbl1/*", "key:vol1/bucket1/db1/tbl2/*" ]; if empty, means all resources + private Set permissions; // example: [ "read", "write" ]; if empty, means no permission + + public Grant() { + } + + public Grant(Set principals, Set resources, Set permissions) { + this.principals = principals; + this.resources = resources; + this.permissions = permissions; + } + + public Set getPrincipals() { + return principals; + } + + public void setPrincipals(Set principals) { + this.principals = principals; + } + + public Set getResources() { + return resources; + } + + public void setResources(Set resources) { + this.resources = resources; + } + + public Set getPermissions() { + return permissions; + } + + public void setPermissions(Set permissions) { + this.permissions = permissions; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o == null || getClass() != o.getClass()) { + return false; + } + + Grant that = (Grant) o; + + return Objects.equals(principals, that.principals) && + Objects.equals(resources, that.resources) && + Objects.equals(permissions, that.permissions); + } + + @Override + public int hashCode() { + return Objects.hash(principals, resources, permissions); + } + + @Override + public String toString() { + return "Grant{" + + "principals=" + principals + + ", resources=" + resources + + ", permissions=" + permissions + + '}'; + } + } +} diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPrincipal.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPrincipal.java index 0dc8b42014..1c3de565be 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPrincipal.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPrincipal.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; +import org.apache.commons.lang3.StringUtils; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -37,6 +38,10 @@ public class RangerPrincipal implements java.io.Serializable { private static final long serialVersionUID = 1L; + public static final String PREFIX_USER = "u:"; + public static final String PREFIX_GROUP = "g:"; + public static final String PREFIX_ROLE = "r:"; + private PrincipalType type; private String name; @@ -95,4 +100,18 @@ public String toString() { } public enum PrincipalType { USER, GROUP, ROLE } + + public static RangerPrincipal toPrincipal(String name) { + if (StringUtils.isBlank(name)) { + return null; + } else if (name.startsWith(PREFIX_USER)) { + return new RangerPrincipal(PrincipalType.USER, name.substring(PREFIX_USER.length())); + } else if (name.startsWith(PREFIX_GROUP)) { + return new RangerPrincipal(PrincipalType.GROUP, name.substring(PREFIX_GROUP.length())); + } else if (name.startsWith(PREFIX_ROLE)) { + return new RangerPrincipal(PrincipalType.ROLE, name.substring(PREFIX_ROLE.length())); + } else { + return new RangerPrincipal(PrincipalType.USER, name); + } + } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java index 71a578b8fd..573c485ff1 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceDef.java @@ -42,6 +42,9 @@ public class RangerServiceDef extends RangerBaseModelObject implements java.io.S public static final String OPTION_ENABLE_DENY_AND_EXCEPTIONS_IN_POLICIES = "enableDenyAndExceptionsInPolicies"; public static final String OPTION_ENABLE_IMPLICIT_CONDITION_EXPRESSION = "enableImplicitConditionExpression"; public static final String OPTION_ENABLE_TAG_BASED_POLICIES = "enableTagBasedPolicies"; + public static final String OPTION_RRN_RESOURCE_SEP_CHAR = "rrnResourceSepChar"; + + public static final char DEFAULT_RRN_RESOURCE_SEP_CHAR = '/'; private String name; private String displayName; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java index 208ba100a8..18b66159f9 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceDefHelper.java @@ -23,7 +23,11 @@ import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.thirdparty.com.google.common.collect.Lists; import org.apache.hadoop.thirdparty.com.google.common.collect.Sets; +import org.apache.ranger.authz.api.RangerAuthzApiErrorCode; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.util.RangerResourceNameParser; import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef; import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; @@ -45,11 +49,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import static org.apache.ranger.authz.util.RangerResourceNameParser.RRN_RESOURCE_TYPE_SEP; +import static org.apache.ranger.plugin.model.RangerServiceDef.OPTION_RRN_RESOURCE_SEP_CHAR; + public class RangerServiceDefHelper { private static final Logger LOG = LoggerFactory.getLogger(RangerServiceDefHelper.class); - public static final String RRN_RESOURCE_SEP = "/"; - static final Map cache = new ConcurrentHashMap<>(); final Delegate delegate; @@ -218,10 +223,18 @@ public Set> getResourceHierarchyKeys(Integer policyType) { return delegate.getResourceHierarchyKeys(policyType); } + public char getRrnResourceSep() { + return delegate.getRrnResourceSepChar(); + } + public String getRrnTemplate(String resourceName) { return delegate.getRrnTemplate(resourceName); } + public RangerResourceNameParser getRrnParser(String resourceName) { + return delegate.getRrnParser(resourceName); + } + public boolean isDataMaskSupported() { return delegate.isDataMaskSupported(); } @@ -429,6 +442,24 @@ public Set expandImpliedAccessGrants(Set accessTypes) { return ret; } + public Map parseResourceToMap(String resource) throws RangerAuthzException { + int sepPos = resource.indexOf(RRN_RESOURCE_TYPE_SEP); + String resourceType = sepPos < 1 ? "" : resource.substring(0, sepPos); + RangerResourceNameParser parser = this.getRrnParser(resourceType); + + if (parser == null) { + throw new RangerAuthzException(RangerAuthzApiErrorCode.INVALID_RESOURCE_TYPE_NOT_VALID, resource, resourceType); + } + + return parser.parseToMap(resource.substring(sepPos + 1)); + } + + public Map parseResourceToPolicyResources(String resource) throws RangerAuthzException { + Map resourceMap = parseResourceToMap(resource); + + return resourceMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> new RangerPolicyResource(e.getValue()))); + } + /** * Not designed for public access. Package level only for testability. */ @@ -448,7 +479,9 @@ static class Delegate { final Set allAccessTypes; final boolean isDataMaskSupported; final boolean isRowFilterSupported; + final char rrnResourceSepChar; final Map rrnTemplates = new HashMap<>(); + final Map rrnParsers = new HashMap<>(); public Delegate(RangerServiceDef serviceDef, boolean checkForCycles) { // NOTE: we assume serviceDef, its name and update time are can never by null. @@ -485,16 +518,26 @@ public Delegate(RangerServiceDef serviceDef, boolean checkForCycles) { } } - impliedGrants = computeImpliedGrants(); - allAccessTypes = Collections.unmodifiableSet(serviceDef.getAccessTypes().stream().map(RangerAccessTypeDef::getName).collect(Collectors.toSet())); - isDataMaskSupported = CollectionUtils.isNotEmpty(hierarchyKeys.get(RangerPolicy.POLICY_TYPE_DATAMASK)); + String optRrnResourceSep = serviceDef.getOptions() != null ? serviceDef.getOptions().get(OPTION_RRN_RESOURCE_SEP_CHAR) : null; + + impliedGrants = computeImpliedGrants(); + allAccessTypes = Collections.unmodifiableSet(serviceDef.getAccessTypes().stream().map(RangerAccessTypeDef::getName).collect(Collectors.toSet())); + isDataMaskSupported = CollectionUtils.isNotEmpty(hierarchyKeys.get(RangerPolicy.POLICY_TYPE_DATAMASK)); isRowFilterSupported = CollectionUtils.isNotEmpty(hierarchyKeys.get(RangerPolicy.POLICY_TYPE_ROWFILTER)); + rrnResourceSepChar = StringUtils.isEmpty(optRrnResourceSep) ? RangerServiceDef.DEFAULT_RRN_RESOURCE_SEP_CHAR : optRrnResourceSep.charAt(0); if (isValid) { orderedResourceNames = buildSortedResourceNames(); for (RangerResourceDef resourceDef : serviceDef.getResources()) { - this.rrnTemplates.put(resourceDef.getName(), getDefaultRrnTemplate(resourceDef)); + try { + RangerResourceNameParser rrnParser = createRrnParser(resourceDef); + + this.rrnParsers.put(resourceDef.getName(), rrnParser); + this.rrnTemplates.put(resourceDef.getName(), rrnParser.getTemplate()); + } catch (RangerAuthzException excp) { + LOG.error("failed to create RRN parser for resource [{}]", resourceDef.getName(), excp); + } } } else { orderedResourceNames = new ArrayList<>(); @@ -566,10 +609,18 @@ public Set> getResourceHierarchyKeys(Integer policyType) { return ret != null ? ret : Collections.emptySet(); } + public char getRrnResourceSepChar() { + return rrnResourceSepChar; + } + public String getRrnTemplate(String resourceName) { return rrnTemplates.get(resourceName); } + public RangerResourceNameParser getRrnParser(String resourceName) { + return rrnParsers.get(resourceName); + } + public boolean isDataMaskSupported() { return isDataMaskSupported; } @@ -897,26 +948,14 @@ public int compareTo(ResourceNameLevel other) { // column:database/table/column // path:bucket/path // key:volume/bucket/key - private String getDefaultRrnTemplate(RangerResourceDef resourceDef) { - List path = new ArrayList<>(); + private RangerResourceNameParser createRrnParser(RangerResourceDef resourceDef) throws RangerAuthzException { + List path = new ArrayList<>(); for (RangerResourceDef resource = resourceDef; resource != null; resource = getResourceDef(resource.getParent(), RangerPolicy.POLICY_TYPE_ACCESS)) { - path.add(0, resource); - } - - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < path.size(); i++) { - RangerResourceDef res = path.get(i); - - if (i > 0) { - sb.append(RRN_RESOURCE_SEP); - } - - sb.append(res.getName()); + path.add(0, resource.getName()); } - return sb.toString(); + return new RangerResourceNameParser(path.toArray(RangerResourceNameParser.EMPTY_ARRAY), rrnResourceSepChar); } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java index 8b7e9b3e42..8736cb4b21 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequest.java @@ -19,6 +19,8 @@ package org.apache.ranger.plugin.policyengine; +import org.apache.ranger.plugin.model.RangerInlinePolicy; + import java.util.Collections; import java.util.Date; import java.util.List; @@ -74,6 +76,10 @@ default Map getResourceElementMatchingScop return Collections.emptyMap(); } + default RangerInlinePolicy getInlinePolicy() { + return null; + } + enum ResourceMatchingScope { SELF, SELF_OR_DESCENDANTS } enum ResourceElementMatchingScope { SELF, SELF_OR_CHILD, SELF_OR_PREFIX } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java index cac69d52fa..29320ae097 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestImpl.java @@ -21,6 +21,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.plugin.model.RangerInlinePolicy; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +60,7 @@ public class RangerAccessRequestImpl implements RangerAccessRequest { private boolean isAccessTypeDelegatedAdmin; private ResourceMatchingScope resourceMatchingScope = ResourceMatchingScope.SELF; private Map resourceElementMatchingScopes = Collections.emptyMap(); + private RangerInlinePolicy inlinePolicy; public RangerAccessRequestImpl() { this(null, null, null, null, null); @@ -236,6 +238,11 @@ public Map getResourceElementMatchingScope return this.resourceElementMatchingScopes; } + @Override + public RangerInlinePolicy getInlinePolicy() { + return inlinePolicy; + } + public void setResourceElementMatchingScopes(Map resourceElementMatchingScopes) { this.resourceElementMatchingScopes = resourceElementMatchingScopes == null ? Collections.emptyMap() : resourceElementMatchingScopes; } @@ -313,6 +320,10 @@ public void setIgnoreDescendantDeny(Boolean isDescendantDenyIgnored) { this.isDescendantDenyIgnored = isDescendantDenyIgnored == null || isDescendantDenyIgnored; } + public void setInlinePolicy(RangerInlinePolicy inlinePolicy) { + this.inlinePolicy = inlinePolicy; + } + public void extractAndSetClientIPAddress(boolean useForwardedIPAddress, String[] trustedProxyAddresses) { String ip = getRemoteIPAddress(); @@ -393,6 +404,7 @@ public StringBuilder toString(StringBuilder sb) { sb.append("resourceElementMatchingScopes={").append(resourceElementMatchingScopes).append("} "); sb.append("clusterName={").append(clusterName).append("} "); sb.append("clusterType={").append(clusterType).append("} "); + sb.append("inlinePolicy={").append(inlinePolicy).append("} "); sb.append("context={"); if (context != null) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java index 2e640d24a7..0a4b8b016a 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestReadOnly.java @@ -19,6 +19,8 @@ package org.apache.ranger.plugin.policyengine; +import org.apache.ranger.plugin.model.RangerInlinePolicy; + import java.util.Collections; import java.util.Date; import java.util.List; @@ -153,4 +155,9 @@ public ResourceMatchingScope getResourceMatchingScope() { public Map getResourceElementMatchingScopes() { return source.getResourceElementMatchingScopes(); } + + @Override + public RangerInlinePolicy getInlinePolicy() { + return source.getInlinePolicy(); + } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java index 5cb032d753..ffb289822b 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessRequestWrapper.java @@ -20,6 +20,7 @@ package org.apache.ranger.plugin.policyengine; import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.plugin.model.RangerInlinePolicy; import java.util.Date; import java.util.List; @@ -148,4 +149,9 @@ public ResourceMatchingScope getResourceMatchingScope() { public Map getResourceElementMatchingScopes() { return request.getResourceElementMatchingScopes(); } + + @Override + public RangerInlinePolicy getInlinePolicy() { + return request.getInlinePolicy(); + } } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java index 0238b7e768..e40b72e928 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java @@ -26,10 +26,12 @@ import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.contextenricher.RangerTagForEval; +import org.apache.ranger.plugin.model.RangerInlinePolicy; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; import org.apache.ranger.plugin.policyengine.gds.GdsAccessResult; +import org.apache.ranger.plugin.policyevaluator.RangerInlinePolicyEvaluator; import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher.MatchType; import org.apache.ranger.plugin.service.RangerDefaultRequestProcessor; @@ -617,6 +619,8 @@ private RangerAccessResult zoneAwareAccessEvaluationWithNoAudit(RangerAccessRequ updateFromGdsResult(ret); + evaluateInlinePolicy(request, ret); + LOG.debug("<== RangerPolicyEngineImpl.zoneAwareAccessEvaluationWithNoAudit({}, policyType ={}): {}", request, policyType, ret); return ret; @@ -1117,6 +1121,22 @@ private void copyFromGdsResult(GdsAccessResult gdsResult, RangerAccessResult res } } + private void evaluateInlinePolicy(RangerAccessRequest request, RangerAccessResult result) { + if (request != null && result != null) { + RangerInlinePolicy inlinePolicy = request.getInlinePolicy(); + + if (inlinePolicy != null) { + LOG.debug("Evaluating inline policy: {}", inlinePolicy); + + RangerInlinePolicyEvaluator evaluator = new RangerInlinePolicyEvaluator(inlinePolicy, this); + + result.incrementEvaluatedPoliciesCount(); + + evaluator.evaluate(request, result); + } + } + } + private static class ServiceConfig { private final Set auditExcludedUsers; private final Set auditExcludedGroups; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerInlinePolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerInlinePolicyEvaluator.java new file mode 100644 index 0000000000..8f2b319d66 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerInlinePolicyEvaluator.java @@ -0,0 +1,307 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ranger.plugin.policyevaluator; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.plugin.model.RangerInlinePolicy; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerPrincipal; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestWrapper; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher; +import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class RangerInlinePolicyEvaluator { + private static final Logger LOG = LoggerFactory.getLogger(RangerInlinePolicyEvaluator.class); + + private static final String PRINCIPAL_G_PUBLIC = RangerPrincipal.PREFIX_GROUP + RangerPolicyEngine.GROUP_PUBLIC; + + private final RangerInlinePolicy policy; + private final RangerPolicyEngine policyEngine; + private final List grants; + + public RangerInlinePolicyEvaluator(RangerInlinePolicy policy, RangerPolicyEngine policyEngine) { + this.policy = policy; + this.policyEngine = policyEngine; + this.grants = toGrantEvaluators(policy); + + LOG.debug("RangerInlinePolicyEvaluator(policy={})", policy); + } + + @Override + public String toString() { + return toString(new StringBuilder()).toString(); + } + + public void evaluate(RangerAccessRequest request, RangerAccessResult result) { + LOG.debug("==> RangerInlinePolicyEvaluator.evaluate({}, {}, {})", policy, request, result); + + if (request != null && result != null) { + boolean isAllowed = result.getIsAccessDetermined() && result.getIsAllowed(); + boolean evalInlinePolicy; + + if (policy.getMode() == null || policy.getMode() == RangerInlinePolicy.Mode.INLINE) { + evalInlinePolicy = true; // request must be allowed by the inline policy + } else if (policy.getMode() == RangerInlinePolicy.Mode.RANGER_AND_INLINE) { + evalInlinePolicy = isAllowed; // if not allowed by Ranger policies, no need to evaluate inline policy + } else { // RANGER_OR_INLINE + evalInlinePolicy = !isAllowed; // if already allowed by Ranger policies, no need to evaluate inline policy + } + + if (evalInlinePolicy) { + isAllowed = isAllowed(request); + + result.setIsAllowed(isAllowed); + result.setIsAccessDetermined(true); + result.setPolicyId(-1); + result.setPolicyVersion(null); + result.setReason("inline-policy"); + } + } + + LOG.debug("<== RangerInlinePolicyEvaluator.evaluate({}, {}, {})", policy, request, result); + } + + private boolean isAllowed(RangerAccessRequest request) { + boolean ret = isAllowedForGrantor(request); + + if (ret && !grants.isEmpty()) { + for (GrantEvaluator evaluator : grants) { + ret = evaluator.isAllowed(request); + + if (ret) { + break; + } + } + } + + return ret; + } + + private boolean isAllowedForGrantor(RangerAccessRequest request) { + final boolean ret; + final RangerPrincipal grantor = RangerPrincipal.toPrincipal(policy.getGrantor()); + + if (grantor != null) { + try (RangerGrantorAccessRequest grantorAccessReq = new RangerGrantorAccessRequest(request, grantor)) { + RangerAccessResult result = policyEngine.evaluatePolicies(grantorAccessReq, RangerPolicy.POLICY_TYPE_ACCESS, null); + + ret = result != null && result.getIsAccessDetermined() && result.getIsAllowed(); + } + } else { + ret = true; + } + + return ret; + } + + private StringBuilder toString(StringBuilder sb) { + sb.append("RangerInlinePolicyEvaluator={"); + + sb.append("policy={").append(policy).append("}"); + + sb.append("}"); + + return sb; + } + + private List toGrantEvaluators(RangerInlinePolicy policy) { + if (CollectionUtils.isEmpty(policy.getGrants())) { + return Collections.emptyList(); + } + + List ret = new ArrayList<>(policy.getGrants().size()); + + for (RangerInlinePolicy.Grant grant : policy.getGrants()) { + GrantEvaluator evaluator = new GrantEvaluator(grant); + + ret.add(evaluator); + } + + return ret; + } + + private class GrantEvaluator { + private final RangerInlinePolicy.Grant grant; + private final Set permissions; + private final Set resourceMatchers = new HashSet<>(); + + public GrantEvaluator(RangerInlinePolicy.Grant grant) { + this.grant = grant; + this.permissions = policyEngine.getServiceDefHelper().expandImpliedAccessGrants(grant.getPermissions()); + + if (grant.getResources() != null) { + for (String resource : grant.getResources()) { + try { + Map policyResources = policyEngine.getServiceDefHelper().parseResourceToPolicyResources(resource); + + RangerDefaultPolicyResourceMatcher resourceMatcher = new RangerDefaultPolicyResourceMatcher(); + + resourceMatcher.setServiceDef(policyEngine.getServiceDef()); + resourceMatcher.setPolicyResources(policyResources, RangerPolicy.POLICY_TYPE_ACCESS); + resourceMatcher.setPluginContext(policyEngine.getPluginContext()); + + resourceMatcher.setServiceDefHelper(policyEngine.getServiceDefHelper()); + resourceMatcher.init(); + + resourceMatchers.add(resourceMatcher); + } catch (RangerAuthzException excp) { + LOG.debug("GrantEvaluator(): invalid resource {}", resource); + } + } + } + + LOG.debug("RangerGrantEvaluator(grant={})", grant); + } + + public boolean isAllowed(RangerAccessRequest request) { + boolean ret = isPrincipalMatch(request) && isPermissionMatch(request) && isResourceMatch(request); + + LOG.debug("isAllowed(grant={}, request={}): ret={}", grant, request, ret); + + return ret; + } + + private boolean isPrincipalMatch(RangerAccessRequest request) { + boolean ret = CollectionUtils.isEmpty(grant.getPrincipals()) || grant.getPrincipals().contains(PRINCIPAL_G_PUBLIC); // match all users; + + if (!ret) { + if (StringUtils.isNotBlank(request.getUser())) { + ret = grant.getPrincipals().contains(RangerPrincipal.PREFIX_USER + request.getUser()); + } + + if (!ret && CollectionUtils.isNotEmpty(request.getUserGroups())) { + for (String groupName : request.getUserGroups()) { + ret = grant.getPrincipals().contains(RangerPrincipal.PREFIX_GROUP + groupName); + + if (ret) { + break; + } + } + } + + if (!ret && CollectionUtils.isNotEmpty(request.getUserRoles())) { + for (String roleName : request.getUserRoles()) { + ret = grant.getPrincipals().contains(RangerPrincipal.PREFIX_ROLE + roleName); + + if (ret) { + break; + } + } + } + } + + LOG.debug("isPrincipalMatch(grant={}, request={}): ret={}", grant, request, ret); + + return ret; + } + + private boolean isPermissionMatch(RangerAccessRequest request) { + boolean ret = StringUtils.isNotBlank(request.getAccessType()) && + CollectionUtils.isNotEmpty(permissions) && + permissions.contains(request.getAccessType()); + + LOG.debug("isPermissionMatch(grant={}, request={}): ret={}", grant, request, ret); + + return ret; + } + + private boolean isResourceMatch(RangerAccessRequest request) { + boolean ret = CollectionUtils.isEmpty(grant.getResources()); // match all resources + + if (!ret) { + for (RangerPolicyResourceMatcher matcher : resourceMatchers) { + ret = matcher.isMatch(request.getResource(), request.getContext()); + + if (ret) { + break; + } + } + } + + LOG.debug("isResourceMatch(grant={}, request={}): ret={}", grant, request, ret); + + return ret; + } + } + + private static class RangerGrantorAccessRequest extends RangerAccessRequestWrapper implements AutoCloseable { + private final String user; + private final Set userGroups; + private final Set userRoles; + private final String savedUser; + private final Set savedUserRoles; + + public RangerGrantorAccessRequest(RangerAccessRequest request, RangerPrincipal grantor) { + super(request, request.getAccessType()); + + user = grantor.getType() == RangerPrincipal.PrincipalType.USER ? grantor.getName() : ""; + userGroups = grantor.getType() == RangerPrincipal.PrincipalType.GROUP ? Collections.singleton(grantor.getName()) : Collections.emptySet(); + userRoles = grantor.getType() == RangerPrincipal.PrincipalType.ROLE ? Collections.singleton(grantor.getName()) : Collections.emptySet(); + + savedUser = RangerAccessRequestUtil.getCurrentUserFromContext(request.getContext()); + savedUserRoles = RangerAccessRequestUtil.getCurrentUserRolesFromContext(request.getContext()); + + RangerAccessRequestUtil.setCurrentUserInContext(getContext(), user); + RangerAccessRequestUtil.setCurrentUserRolesInContext(getContext(), userRoles); + } + + @Override + public void close() { + RangerAccessRequestUtil.setCurrentUserInContext(getContext(), savedUser); + RangerAccessRequestUtil.setCurrentUserRolesInContext(getContext(), savedUserRoles); + } + + @Override + public String getUser() { + return user; + } + + @Override + public Set getUserGroups() { + return userGroups; + } + + @Override + public Set getUserRoles() { + return userRoles; + } + + @Override + public RangerInlinePolicy getInlinePolicy() { + return null; + } + } +} diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java index 3462a16628..20278f46d2 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/ResourceMatcher.java @@ -39,11 +39,13 @@ import java.util.Stack; abstract class ResourceMatcher { - static final int DYNAMIC_EVALUATION_PENALTY = 8; - private static final Logger LOG = LoggerFactory.getLogger(ResourceMatcher.class); - protected final String value; - protected final RangerRequestExprResolver exprResolver; - protected StringTokenReplacer tokenReplacer; + private static final Logger LOG = LoggerFactory.getLogger(ResourceMatcher.class); + + static final int DYNAMIC_EVALUATION_PENALTY = 8; + + protected final String value; + protected final RangerRequestExprResolver exprResolver; + protected StringTokenReplacer tokenReplacer; ResourceMatcher(String value, Map options) { this.value = value; @@ -55,6 +57,81 @@ abstract class ResourceMatcher { } } + abstract boolean isMatch(String resourceValue, Map evalContext); + + abstract boolean isPrefixMatch(String resourceValue, Map evalContext); + + abstract boolean isChildMatch(String resourceValue, Map evalContext); + + abstract int getPriority(); + + @Override + public String toString() { + return this.getClass().getName() + "(" + this.value + ")"; + } + + final boolean isMatch(String resourceValue, ResourceElementMatchingScope matchingScope, Map evalContext) { + final ResourceElementMatchType matchType = getMatchType(resourceValue, matchingScope, evalContext); + + return isMatch(matchType, matchingScope); + } + + final ResourceElementMatchType getMatchType(String resourceValue, ResourceElementMatchingScope matchingScope, Map evalContext) { + ResourceElementMatchType ret = ResourceElementMatchType.NONE; + + if (isMatch(resourceValue, evalContext)) { + ret = ResourceElementMatchType.SELF; + } else { + if (matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX) { + if (isPrefixMatch(resourceValue, evalContext)) { + ret = ResourceElementMatchType.PREFIX; + } + } else if (matchingScope == ResourceElementMatchingScope.SELF_OR_CHILD) { + if (isChildMatch(resourceValue, evalContext)) { + ret = ResourceElementMatchType.CHILD; + } + } + } + + return ret; + } + + boolean isMatchAny() { + return value != null && value.isEmpty(); + } + + boolean getNeedsDynamicEval() { + return exprResolver != null || tokenReplacer != null; + } + + void setDelimiters(char startDelimiterChar, char endDelimiterChar, char escapeChar, String tokenPrefix) { + LOG.debug("==> setDelimiters(value= {}, startDelimiter={}, endDelimiter={}, escapeChar={}, prefix={}", value, startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); + + if (exprResolver != null || StringTokenReplacer.hasToken(value, startDelimiterChar, endDelimiterChar, escapeChar)) { + tokenReplacer = new StringTokenReplacer(startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); + } + + LOG.debug("<== setDelimiters(value= {}, startDelimiter={}, endDelimiter={}, escapeChar={}, prefix={}", value, startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); + } + + String getExpandedValue(Map evalContext) { + String ret = value; + + if (exprResolver != null) { + RangerAccessRequest accessRequest = RangerAccessRequestUtil.getRequestFromContext(evalContext); + + if (accessRequest != null) { + ret = exprResolver.resolveExpressions(accessRequest); + } + } + + if (tokenReplacer != null) { + ret = tokenReplacer.replaceTokens(ret, evalContext); + } + + return ret; + } + public static boolean startsWithAnyChar(String value, String startChars) { boolean ret = false; @@ -213,81 +290,6 @@ static List splitOnTokens(String text) { } } - @Override - public String toString() { - return this.getClass().getName() + "(" + this.value + ")"; - } - - abstract boolean isMatch(String resourceValue, Map evalContext); - - abstract boolean isPrefixMatch(String resourceValue, Map evalContext); - - abstract boolean isChildMatch(String resourceValue, Map evalContext); - - final boolean isMatch(String resourceValue, ResourceElementMatchingScope matchingScope, Map evalContext) { - final ResourceElementMatchType matchType = getMatchType(resourceValue, matchingScope, evalContext); - - return isMatch(matchType, matchingScope); - } - - final ResourceElementMatchType getMatchType(String resourceValue, ResourceElementMatchingScope matchingScope, Map evalContext) { - ResourceElementMatchType ret = ResourceElementMatchType.NONE; - - if (isMatch(resourceValue, evalContext)) { - ret = ResourceElementMatchType.SELF; - } else { - if (matchingScope == ResourceElementMatchingScope.SELF_OR_PREFIX) { - if (isPrefixMatch(resourceValue, evalContext)) { - ret = ResourceElementMatchType.PREFIX; - } - } else if (matchingScope == ResourceElementMatchingScope.SELF_OR_CHILD) { - if (isChildMatch(resourceValue, evalContext)) { - ret = ResourceElementMatchType.CHILD; - } - } - } - - return ret; - } - - abstract int getPriority(); - - boolean isMatchAny() { - return value != null && value.isEmpty(); - } - - boolean getNeedsDynamicEval() { - return exprResolver != null || tokenReplacer != null; - } - - void setDelimiters(char startDelimiterChar, char endDelimiterChar, char escapeChar, String tokenPrefix) { - LOG.debug("==> setDelimiters(value= {}, startDelimiter={}, endDelimiter={}, escapeChar={}, prefix={}", value, startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); - - if (exprResolver != null || StringTokenReplacer.hasToken(value, startDelimiterChar, endDelimiterChar, escapeChar)) { - tokenReplacer = new StringTokenReplacer(startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); - } - - LOG.debug("<== setDelimiters(value= {}, startDelimiter={}, endDelimiter={}, escapeChar={}, prefix={}", value, startDelimiterChar, endDelimiterChar, escapeChar, tokenPrefix); - } - - String getExpandedValue(Map evalContext) { - String ret = value; - - if (exprResolver != null) { - RangerAccessRequest accessRequest = RangerAccessRequestUtil.getRequestFromContext(evalContext); - - if (accessRequest != null) { - ret = exprResolver.resolveExpressions(accessRequest); - } - } - - if (tokenReplacer != null) { - ret = tokenReplacer.replaceTokens(ret, evalContext); - } - - return ret; - } - public static class PriorityComparator implements Comparator, Serializable { @Override public int compare(ResourceMatcher me, ResourceMatcher other) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java index 740425ee11..52a643eadd 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java @@ -37,6 +37,8 @@ import java.util.TreeSet; public class RangerAccessRequestUtil { + private static final Logger LOG = LoggerFactory.getLogger(RangerAccessRequestUtil.class); + public static final String KEY_CONTEXT_TAGS = "TAGS"; public static final String KEY_CONTEXT_TAG_OBJECT = "TAG_OBJECT"; public static final String KEY_CONTEXT_RESOURCE = "RESOURCE"; @@ -56,7 +58,7 @@ public class RangerAccessRequestUtil { public static final String KEY_CONTEXT_GDS_RESULT = "_GDS_RESULT"; public static final String KEY_CONTEXT_IS_REQUEST_PREPROCESSED = "ISREQUESTPREPROCESSED"; public static final String KEY_CONTEXT_RESOURCE_ZONE_NAMES = "RESOURCE_ZONE_NAMES"; - private static final Logger LOG = LoggerFactory.getLogger(RangerAccessRequestUtil.class); + public static final String KEY_CONTEXT_ACL_ENFORCER = "_ACL_ENFORCER"; private RangerAccessRequestUtil() { // to avoid instantiation @@ -451,4 +453,20 @@ public static void setAccessTypeResult(Map context, String acces results.putIfAbsent(accessType, result); } } + + public static String getAclEnforcerOrDefault(Map context, String defaultValue) { + Object ret = context != null ? context.get(KEY_CONTEXT_ACL_ENFORCER) : null; + + return ret instanceof String ? (String) ret : defaultValue; + } + + public static void setAclEnforcer(Map context, String aclEnforcer) { + if (context != null) { + if (aclEnforcer != null) { + context.put(KEY_CONTEXT_ACL_ENFORCER, aclEnforcer); + } else { + context.remove(KEY_CONTEXT_ACL_ENFORCER); + } + } + } } diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyevaluator/TestInlinePolicyEvaluator.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyevaluator/TestInlinePolicyEvaluator.java new file mode 100644 index 0000000000..cffdf73398 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyevaluator/TestInlinePolicyEvaluator.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ranger.plugin.policyevaluator; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; +import org.apache.ranger.plugin.policyengine.RangerPluginContext; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; +import org.apache.ranger.plugin.util.ServiceDefUtil; +import org.apache.ranger.plugin.util.ServicePolicies; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TestInlinePolicyEvaluator { + Gson gsonBuilder; + + @Before + public void init() { + gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSSZ") + .setPrettyPrinting() + .registerTypeAdapter(RangerAccessRequest.class, new RangerAccessRequestDeserializer()) + .registerTypeAdapter(RangerAccessResource.class, new RangerResourceDeserializer()) + .create(); + } + + @After + public void cleanup() { + } + + @Test + public void testOzoneInlinePolicies() throws IOException { + runTests("/policyevaluator/test_inline_policies_ozone.json"); + } + + private void runTests(String resourceName) throws IOException { + try (InputStream inStream = this.getClass().getResourceAsStream(resourceName)) { + assertNotNull("failed to find resource '" + resourceName + "'", inStream); + + InputStreamReader reader = new InputStreamReader(inStream); + + runTestCase(gsonBuilder.fromJson(reader, PolicyEngineTestCase.class)); + } + } + + private void runTestCase(PolicyEngineTestCase testCase) { + ServicePolicies servicePolicies = testCase.servicePolicies; + RangerServiceDef serviceDef = servicePolicies.getServiceDef(); + + ServiceDefUtil.normalize(serviceDef); + + RangerPolicyEngineOptions policyEngineOptions = new RangerPolicyEngineOptions(); + RangerPluginContext pluginContext = new RangerPluginContext(new RangerPluginConfig(serviceDef.getName(), servicePolicies.getServiceName(), null, "cl1", "on-prem", policyEngineOptions)); + RangerPolicyEngine policyEngine = new RangerPolicyEngineImpl(servicePolicies, pluginContext, null); + RangerAccessResultProcessor auditHandler = new RangerDefaultAuditHandler(pluginContext.getConfig()); + + for (TestData test : testCase.tests) { + RangerAccessResult expected = test.result; + RangerAccessRequest request = test.request; + + RangerAccessResult result = policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, auditHandler); + + assertNotNull("result was null! - " + test.name, result); + assertEquals("isAllowed mismatched! - " + test.name, expected.getIsAllowed(), result.getIsAllowed()); + assertEquals("isAudited mismatched! - " + test.name, expected.getIsAudited(), result.getIsAudited()); + assertEquals("policyId mismatched! - " + test.name, expected.getPolicyId(), result.getPolicyId()); + } + } + + static class PolicyEngineTestCase { + ServicePolicies servicePolicies; + public List tests; + } + + static class TestData { + public String name; + public RangerAccessRequest request; + public RangerAccessResult result; + } + + class RangerAccessRequestDeserializer implements JsonDeserializer { + @Override + public RangerAccessRequest deserialize(JsonElement jsonObj, Type type, JsonDeserializationContext context) throws JsonParseException { + RangerAccessRequestImpl ret = gsonBuilder.fromJson(jsonObj, RangerAccessRequestImpl.class); + + ret.setAccessType(ret.getAccessType()); // to force computation of isAccessTypeAny and isAccessTypeDelegatedAdmin + + if (ret.getAccessTime() == null) { + ret.setAccessTime(new Date()); + } + + return ret; + } + } + + class RangerResourceDeserializer implements JsonDeserializer { + @Override + public RangerAccessResource deserialize(JsonElement jsonObj, Type type, JsonDeserializationContext context) throws JsonParseException { + return gsonBuilder.fromJson(jsonObj, RangerAccessResourceImpl.class); + } + } +} diff --git a/agents-common/src/test/resources/policyevaluator/test_inline_policies_ozone.json b/agents-common/src/test/resources/policyevaluator/test_inline_policies_ozone.json new file mode 100644 index 0000000000..bb41f4bbdd --- /dev/null +++ b/agents-common/src/test/resources/policyevaluator/test_inline_policies_ozone.json @@ -0,0 +1,233 @@ +{ + "servicePolicies": { + "serviceName": "dev_ozone", "serviceId": 1, + + "serviceDef":{ + "id": 1, "name":"ozone", + "resources":[ + { "name": "volume", "level": 1, "parent": "", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Volume", "description": "Volume" }, + { "name": "bucket", "level": 2, "parent": "volume", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerURLResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Bucket", "description": "Bucket" }, + { "name": "key", "level": 3, "parent": "bucket", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Key", "description": "Key" }, + { "name": "role", "level": 4, "parent": "", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": false }, "label": "Role", "description": "Role" } + ], + "accessTypes":[ + { "name": "read", "label": "Read" }, + { "name": "write", "label": "Write" }, + { "name": "create", "label": "Create" }, + { "name": "list", "label": "List" }, + { "name": "delete", "label": "Delete" }, + { "name": "read_acl", "label": "Read_ACL" }, + { "name": "write_acl", "label": "Write_ACL" }, + { "name": "all", "label": "All", "impliedGrants": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl" ] }, + { "name": "assume_role", "label": "Assume_Role" } + ] + }, + "policies": [ + { "id": 100, "name": "role: data-reader", "isEnabled": true, "isAuditEnabled": true, + "resources": { "role": { "values": [ "data-reader" ] } }, + "policyItems":[ + { "accesses": [ { "type": "assume_role" } ], "users":[ "svc-iceberg-rest-catalog" ] } + ] + }, + { "id": 101, "name": "role: data-all-access", "isEnabled": true, "isAuditEnabled": true, + "resources": { "role": { "values": [ "data-all-access" ] } }, + "policyItems":[ + { "accesses": [ { "type": "assume_role" } ], "users":[ "svc-iceberg-rest-catalog" ] } + ] + }, + { "id": 200, "name": "iceberg-data", "isEnabled": true, "isAuditEnabled": true, + "resources": { "volume": { "values": [ "s3v" ] }, "bucket": { "values": [ "iceberg" ] }, "key": { "values": [ "*" ] } }, + "policyItems":[ + { "accesses": [ { "type": "read" }, { "type": "list" }, { "type": "read_acl" } ], "users": [ "analyst" ], "roles":[ "data-reader" ] }, + { "accesses": [ { "type": "all" } ], "users": [ "svc-etl" ], "roles":[ "data-all-access" ] } + ] + } + ], + "tagPolicies": { }, + "securityZones": { } + }, + + "tests":[ + { "name": "ALLOW 'assume_role data-reader;' for svc-iceberg-rest-catalog", + "request": { + "resource": { "elements": { "role": "data-reader" } }, "accessType": "assume_role", "user": "svc-iceberg-rest-catalog" + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 100} + }, + { "name": "ALLOW 'assume_role data-all-access;' for svc-iceberg-rest-catalog", + "request": { + "resource": { "elements": { "role": "data-all-access" } }, "accessType": "assume_role", "user": "svc-iceberg-rest-catalog" + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 101} + }, + { "name": "DENY 'assume_role data-reader;' for user1", + "request": { + "resource": { "elements": { "role": "data-reader" } }, "accessType": "assume_role", "user": "user1" + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "DENY 'assume_role data-all-access;' for user1", + "request": { + "resource": { "elements": { "role": "data-all-access" } }, "accessType": "assume_role", "user": "user1" + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "ALLOW 'read s3v/iceberg/key1;' for inline-policy-reader", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "INLINE" } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": -1} + }, + { "name": "DENY 'write s3v/iceberg/key1;' for inline-policy-reader", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "accessType": "write", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "INLINE" } + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "DENY 'write s3v/warehouse/key1;' for inline-policy-reader", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "warehouse", "key": "key1" } }, "accessType": "write", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "INLINE" } + }, + "result": { "isAudited": false, "isAllowed": false, "policyId": -1} + }, + { "name": "ALLOW 'read s3v/iceberg/key1;' for inline-policy-all-access", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "accessType": "read", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "INLINE" } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": -1} + }, + { "name": "ALLOW 'write s3v/iceberg/key1;' for inline-policy-all-access", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "INLINE" } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": -1} + }, + { "name": "DENY 'write s3v/warehouse/key1;' for inline-policy-all-access", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "warehouse", "key": "key1" } }, "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "INLINE" } + }, + "result": { "isAudited": false, "isAllowed": false, "policyId": -1} + }, + + + { "name": "ALLOW 'read s3v/iceberg/key1;' for user=analyst; inline-policy for key2 with mode RANGER_OR_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "analyst", "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "RANGER_OR_INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "read", "list", "read_acl" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 200 } + }, + { "name": "DENY 'read s3v/iceberg/key1;' for user=analyst; inline-policy for key2 with mode RANGER_AND_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "analyst", "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "RANGER_AND_INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "read", "list", "read_acl" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "DENY 'read s3v/iceberg/key1;' for user=analyst; inline-policy for key2 with mode INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "analyst", "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "read", "list", "read_acl" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "ALLOW 'read s3v/iceberg/key2;' for user=analyst; inline-policy for key2 with mode RANGER_AND_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key2" } }, "user": "analyst", "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "RANGER_OR_INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "read", "list", "read_acl" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 200 } + }, + { "name": "ALLOW 'read s3v/iceberg/key2;' for user=analyst; inline-policy for key2 with mode INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key2" } }, "user": "analyst", "accessType": "read", + "inlinePolicy": { "grantor": "r:data-reader", "mode": "INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2" ], "permissions": [ "read", "list", "read_acl" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": -1 } + }, + + + { "name": "ALLOW 'write s3v/iceberg/key1;' for user=svc-etl; inline-policy for key2 with mode RANGER_OR_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "svc-etl", "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "RANGER_OR_INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "all" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 200 } + }, + { "name": "DENY 'write s3v/iceberg/key1;' for user=svc-etl; inline-policy for key2 with mode RANGER_AND_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "svc-etl", "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "RANGER_AND_INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "all" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "DENY 'read s3v/iceberg/key1;' for user=svc-etl; inline-policy for key2 with mode INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key1" } }, "user": "svc-etl", "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "INLINE", + "grants": [ + { "principals": [ "u:analyst" ], "resources": [ "key:s3v/iceberg/key2"], "permissions": [ "all" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": false, "policyId": -1} + }, + { "name": "ALLOW 'write s3v/iceberg/key2;' for user=svc-etl; inline-policy for key2 with mode RANGER_AND_INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key2" } }, "user": "svc-etl", "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "RANGER_OR_INLINE", + "grants": [ + { "principals": [ "u:svc-etl" ], "resources": [ "key:s3v/iceberg/key2" ], "permissions": [ "all" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": 200 } + }, + { "name": "ALLOW 'write s3v/iceberg/key2;' for user=svc-etl; inline-policy for key2 with mode INLINE", + "request": { + "resource": { "elements": { "volume": "s3v", "bucket": "iceberg", "key": "key2" } }, "user": "svc-etl", "accessType": "write", + "inlinePolicy": { "grantor": "r:data-all-access", "mode": "INLINE", + "grants": [ + { "principals": [ "u:svc-etl" ], "resources": [ "key:s3v/iceberg/key2" ], "permissions": [ "all" ] } + ] + } + }, + "result": { "isAudited": true, "isAllowed": true, "policyId": -1 } + } + ] +} + diff --git a/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java b/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java index 5000a5a439..cf789f482c 100644 --- a/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java +++ b/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java @@ -36,24 +36,34 @@ public class RangerResourceNameParser { private static final Logger LOG = LoggerFactory.getLogger(RangerResourceNameParser.class); - public static final char ESCAPE_CHAR = '\\'; - public static final char SEPARATOR_CHAR = '/'; + public static final String[] EMPTY_ARRAY = new String[0]; + public static final char RRN_RESOURCE_TYPE_SEP = ':'; - private static final String SEPARATOR_STRING = String.valueOf(SEPARATOR_CHAR); - private static final String ESCAPED_SEPARATOR = "\\\\" + SEPARATOR_STRING; - private static final Pattern SEPARATOR_PATTERN = Pattern.compile(SEPARATOR_STRING); - private static final String[] EMPTY_ARRAY = new String[0]; + private static final char ESCAPE_CHAR = '\\'; + private static final String ESCAPE_STRING = "\\\\"; + private final char separatorChar; + private final String separatorString; + private final String escapedSeparator; + private final Pattern separatorPattern; private final String template; // examples: database/table/column, bucket/volume/path private final String[] resources; // examples: [database, table, column], [bucket, volume, path] - public RangerResourceNameParser(String template) throws RangerAuthzException { + public RangerResourceNameParser(String[] resourcePath, char separatorChar) throws RangerAuthzException { + this(StringUtils.join(resourcePath, separatorChar), separatorChar); + } + + public RangerResourceNameParser(String template, char separatorChar) throws RangerAuthzException { if (StringUtils.isBlank(template)) { throw new RangerAuthzException(INVALID_RESOURCE_TEMPLATE_EMPTY_VALUE); } - this.template = template; - this.resources = template.split(SEPARATOR_STRING); // assumption: '/' is not a valid character in resource names + this.separatorChar = separatorChar; + this.separatorString = String.valueOf(separatorChar); + this.escapedSeparator = ESCAPE_STRING + separatorString; + this.separatorPattern = Pattern.compile(separatorString); + this.template = template; + this.resources = template.split(separatorString); // assumption: separatorChar is not a valid character in resource names } public String getTemplate() { @@ -93,9 +103,9 @@ public String[] parseToArray(final String resourceName) throws RangerAuthzExcept continue; } - } else if (c == SEPARATOR_CHAR) { + } else if (c == separatorChar) { if (!isInEscape) { - if (!isLastToken) { // for last token, '/' is not a separator + if (!isLastToken) { // for last token, separatorChar is not a separator ret[idxToken++] = token.toString(); token.setLength(0); @@ -151,12 +161,12 @@ public String toResourceName(String[] values) { value = ""; } - if (!isLast) { // escape '/' in all but the last resource + if (!isLast) { // escape separatorChar in all but the last resource value = escapeIfNeeded(value); } if (i > 0) { - ret.append(SEPARATOR_CHAR); + ret.append(separatorChar); } ret.append(value); @@ -182,12 +192,12 @@ public String toResourceName(Map values) { value = ""; } - if (!isLast) { // escape '/' in all but the last resource + if (!isLast) { // escape separatorChar in all but the last resource value = escapeIfNeeded(value); } if (i > 0) { - ret.append(SEPARATOR_CHAR); + ret.append(separatorChar); } ret.append(value); @@ -202,13 +212,13 @@ public String toResourceName(Map values) { public String toString() { return "RangerResourceTemplate{" + "template=" + template + - ", resources='" + String.join(SEPARATOR_STRING, resources) + "'" + + ", resources='" + String.join(separatorString, resources) + "'" + "}"; } private String escapeIfNeeded(String value) { - if (value.contains(SEPARATOR_STRING)) { - return SEPARATOR_PATTERN.matcher(value).replaceAll(ESCAPED_SEPARATOR); + if (value.contains(separatorString)) { + return separatorPattern.matcher(value).replaceAll(escapedSeparator); } else { return value; } diff --git a/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java b/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java index 8c137203bb..06e0fe564b 100644 --- a/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java +++ b/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java @@ -31,10 +31,13 @@ import static org.apache.ranger.authz.api.RangerAuthzApiErrorCode.INVALID_RESOURCE_TEMPLATE_EMPTY_VALUE; import static org.apache.ranger.authz.api.RangerAuthzApiErrorCode.INVALID_RESOURCE_TYPE_NOT_VALID; import static org.apache.ranger.authz.api.RangerAuthzApiErrorCode.INVALID_RESOURCE_VALUE; +import static org.apache.ranger.authz.util.RangerResourceNameParser.RRN_RESOURCE_TYPE_SEP; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; public class TestRangerResourceNameParser { + private static final char RRN_RESOURCE_SEP_CHAR = '/'; + @Test public void testValidTemplates() throws Exception { Object[][] testData = { @@ -59,7 +62,7 @@ public void testValidTemplates() throws Exception { String template = (String) test[0]; String resourceType = (String) test[1]; int resourceCount = (Integer) test[2]; - RangerResourceNameParser resourceTemplate = new RangerResourceNameParser(template); + RangerResourceNameParser resourceTemplate = new RangerResourceNameParser(template, RRN_RESOURCE_SEP_CHAR); assertEquals(resourceType, resourceTemplate.getResourceType(), template); assertEquals(resourceCount, resourceTemplate.count(), template); @@ -72,7 +75,7 @@ public void testValidTemplates() throws Exception { } @Test - public void testInvalidTemplates() throws Exception { + public void testInvalidTemplates() { String[] templates = { null, "", @@ -80,7 +83,7 @@ public void testInvalidTemplates() throws Exception { }; for (String template : templates) { - RangerAuthzException excp = assertThrowsExactly(RangerAuthzException.class, () -> new RangerResourceNameParser(template), template); + RangerAuthzException excp = assertThrowsExactly(RangerAuthzException.class, () -> new RangerResourceNameParser(template, RRN_RESOURCE_SEP_CHAR), template); assertEquals(INVALID_RESOURCE_TEMPLATE_EMPTY_VALUE.getCode(), excp.getErrorCode().getCode(), template); } @@ -300,13 +303,13 @@ public void testResourceNameFromArrayS3() throws Exception { private static Map getHiveTemplates() throws Exception { Map ret = new HashMap<>(); - ret.put("database", new RangerResourceNameParser("database")); - ret.put("table", new RangerResourceNameParser("database/table")); - ret.put("column", new RangerResourceNameParser("database/table/column")); - ret.put("udf", new RangerResourceNameParser("database/udf")); - ret.put("url", new RangerResourceNameParser("url")); - ret.put("hiveservice", new RangerResourceNameParser("hiveservice")); - ret.put("global", new RangerResourceNameParser("global")); + ret.put("database", new RangerResourceNameParser("database", RRN_RESOURCE_SEP_CHAR)); + ret.put("table", new RangerResourceNameParser("database/table", RRN_RESOURCE_SEP_CHAR)); + ret.put("column", new RangerResourceNameParser("database/table/column", RRN_RESOURCE_SEP_CHAR)); + ret.put("udf", new RangerResourceNameParser("database/udf", RRN_RESOURCE_SEP_CHAR)); + ret.put("url", new RangerResourceNameParser("url", RRN_RESOURCE_SEP_CHAR)); + ret.put("hiveservice", new RangerResourceNameParser("hiveservice", RRN_RESOURCE_SEP_CHAR)); + ret.put("global", new RangerResourceNameParser("global", RRN_RESOURCE_SEP_CHAR)); return ret; } @@ -314,8 +317,8 @@ private static Map getHiveTemplates() throws E private static Map getS3Templates() throws Exception { Map ret = new HashMap<>(); - ret.put("bucket", new RangerResourceNameParser("bucket")); - ret.put("path", new RangerResourceNameParser("bucket/path")); + ret.put("bucket", new RangerResourceNameParser("bucket", RRN_RESOURCE_SEP_CHAR)); + ret.put("path", new RangerResourceNameParser("bucket/path", RRN_RESOURCE_SEP_CHAR)); return ret; } @@ -323,8 +326,8 @@ private static Map getS3Templates() throws Exc private static Map getAdlsGen2Templates() throws Exception { Map ret = new HashMap<>(); - ret.put("container", new RangerResourceNameParser("storageaccount/container")); - ret.put("relativepath", new RangerResourceNameParser("storageaccount/container/relativepath")); + ret.put("container", new RangerResourceNameParser("storageaccount/container", RRN_RESOURCE_SEP_CHAR)); + ret.put("relativepath", new RangerResourceNameParser("storageaccount/container/relativepath", RRN_RESOURCE_SEP_CHAR)); return ret; } @@ -332,25 +335,25 @@ private static Map getAdlsGen2Templates() thro private static Map getTrinoTemplates() throws Exception { Map ret = new HashMap<>(); - ret.put("catalog", new RangerResourceNameParser("catalog")); - ret.put("schema", new RangerResourceNameParser("catalog/schema")); - ret.put("table", new RangerResourceNameParser("catalog/schema/table")); - ret.put("column", new RangerResourceNameParser("catalog/schema/table/column")); - ret.put("trinouser", new RangerResourceNameParser("trinouser")); - ret.put("systemproperty", new RangerResourceNameParser("systemproperty")); - ret.put("sessionproperty", new RangerResourceNameParser("catalog/sessionproperty")); - ret.put("function", new RangerResourceNameParser("function")); - ret.put("procedure", new RangerResourceNameParser("catalog/schema/procedure")); - ret.put("schemafunction", new RangerResourceNameParser("catalog/schema/schemafunction")); - ret.put("queryid", new RangerResourceNameParser("queryid")); - ret.put("sysinfo", new RangerResourceNameParser("sysinfo")); - ret.put("role", new RangerResourceNameParser("role")); + ret.put("catalog", new RangerResourceNameParser("catalog", RRN_RESOURCE_SEP_CHAR)); + ret.put("schema", new RangerResourceNameParser("catalog/schema", RRN_RESOURCE_SEP_CHAR)); + ret.put("table", new RangerResourceNameParser("catalog/schema/table", RRN_RESOURCE_SEP_CHAR)); + ret.put("column", new RangerResourceNameParser("catalog/schema/table/column", RRN_RESOURCE_SEP_CHAR)); + ret.put("trinouser", new RangerResourceNameParser("trinouser", RRN_RESOURCE_SEP_CHAR)); + ret.put("systemproperty", new RangerResourceNameParser("systemproperty", RRN_RESOURCE_SEP_CHAR)); + ret.put("sessionproperty", new RangerResourceNameParser("catalog/sessionproperty", RRN_RESOURCE_SEP_CHAR)); + ret.put("function", new RangerResourceNameParser("function", RRN_RESOURCE_SEP_CHAR)); + ret.put("procedure", new RangerResourceNameParser("catalog/schema/procedure", RRN_RESOURCE_SEP_CHAR)); + ret.put("schemafunction", new RangerResourceNameParser("catalog/schema/schemafunction", RRN_RESOURCE_SEP_CHAR)); + ret.put("queryid", new RangerResourceNameParser("queryid", RRN_RESOURCE_SEP_CHAR)); + ret.put("sysinfo", new RangerResourceNameParser("sysinfo", RRN_RESOURCE_SEP_CHAR)); + ret.put("role", new RangerResourceNameParser("role", RRN_RESOURCE_SEP_CHAR)); return ret; } private Map parseToMap(String resource, Map templates) throws RangerAuthzException { - String[] resourceParts = resource.split(":", 2); + String[] resourceParts = resource.split(String.valueOf(RRN_RESOURCE_TYPE_SEP), 2); String resourceType = resourceParts.length > 0 ? resourceParts[0] : null; String resourceValue = resourceParts.length > 1 ? resourceParts[1] : null; RangerResourceNameParser template = templates.get(resourceType); diff --git a/distro/src/main/assembly/admin-web.xml b/distro/src/main/assembly/admin-web.xml index 17a4408bb5..15c0f0f62e 100644 --- a/distro/src/main/assembly/admin-web.xml +++ b/distro/src/main/assembly/admin-web.xml @@ -235,6 +235,7 @@ org.apache.tomcat:tomcat-annotations-api* org.eclipse.jdt.core.compiler:ecj:jar:P20140317-1600 org.apache.hadoop:hadoop-auth:jar:${hadoop.version} + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util org.slf4j:slf4j-api:jar:${slf4j.version} diff --git a/distro/src/main/assembly/hbase-agent.xml b/distro/src/main/assembly/hbase-agent.xml index 3748b371b7..27cce24c92 100644 --- a/distro/src/main/assembly/hbase-agent.xml +++ b/distro/src/main/assembly/hbase-agent.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/hdfs-agent.xml b/distro/src/main/assembly/hdfs-agent.xml index 8432ea8951..f88500a0f7 100644 --- a/distro/src/main/assembly/hdfs-agent.xml +++ b/distro/src/main/assembly/hdfs-agent.xml @@ -72,6 +72,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/hive-agent.xml b/distro/src/main/assembly/hive-agent.xml index f5f8b5bf29..b407ded855 100644 --- a/distro/src/main/assembly/hive-agent.xml +++ b/distro/src/main/assembly/hive-agent.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/kms.xml b/distro/src/main/assembly/kms.xml index 1aedfd9b0a..1e5e7e0be1 100755 --- a/distro/src/main/assembly/kms.xml +++ b/distro/src/main/assembly/kms.xml @@ -213,6 +213,7 @@ org.apache.hadoop:hadoop-common:jar:${hadoop.version} org.apache.hadoop:hadoop-auth:jar:${hadoop.version} org.apache.solr:solr-solrj:jar:${solr.version} + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util com.kstruct:gethostname4j:jar:${kstruct.gethostname4j.version} diff --git a/distro/src/main/assembly/knox-agent.xml b/distro/src/main/assembly/knox-agent.xml index d407777bfa..eee995a73d 100644 --- a/distro/src/main/assembly/knox-agent.xml +++ b/distro/src/main/assembly/knox-agent.xml @@ -45,6 +45,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-atlas.xml b/distro/src/main/assembly/plugin-atlas.xml index 5d6b24adcb..44e18cd378 100644 --- a/distro/src/main/assembly/plugin-atlas.xml +++ b/distro/src/main/assembly/plugin-atlas.xml @@ -45,6 +45,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-elasticsearch.xml b/distro/src/main/assembly/plugin-elasticsearch.xml index 2f3f84d40a..53e99622cc 100644 --- a/distro/src/main/assembly/plugin-elasticsearch.xml +++ b/distro/src/main/assembly/plugin-elasticsearch.xml @@ -49,6 +49,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-es org.apache.ranger:ranger-audit-dest-hdfs + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-kafka.xml b/distro/src/main/assembly/plugin-kafka.xml index 4db4b3edee..051cfe9edc 100644 --- a/distro/src/main/assembly/plugin-kafka.xml +++ b/distro/src/main/assembly/plugin-kafka.xml @@ -40,6 +40,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-kafka-plugin org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common diff --git a/distro/src/main/assembly/plugin-kms.xml b/distro/src/main/assembly/plugin-kms.xml index 2d334528c7..704a083b0c 100755 --- a/distro/src/main/assembly/plugin-kms.xml +++ b/distro/src/main/assembly/plugin-kms.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-kylin.xml b/distro/src/main/assembly/plugin-kylin.xml index 8b2b737482..be7a3de806 100644 --- a/distro/src/main/assembly/plugin-kylin.xml +++ b/distro/src/main/assembly/plugin-kylin.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-ozone.xml b/distro/src/main/assembly/plugin-ozone.xml index 4a39b00d7c..4c9456afb6 100644 --- a/distro/src/main/assembly/plugin-ozone.xml +++ b/distro/src/main/assembly/plugin-ozone.xml @@ -79,6 +79,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-presto.xml b/distro/src/main/assembly/plugin-presto.xml index 4d61197710..d0abae771d 100644 --- a/distro/src/main/assembly/plugin-presto.xml +++ b/distro/src/main/assembly/plugin-presto.xml @@ -56,6 +56,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-solr.xml b/distro/src/main/assembly/plugin-solr.xml index d1b4471a1d..27cd5e5978 100644 --- a/distro/src/main/assembly/plugin-solr.xml +++ b/distro/src/main/assembly/plugin-solr.xml @@ -39,6 +39,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-sqoop.xml b/distro/src/main/assembly/plugin-sqoop.xml index b1ade54bf5..3e5c30f535 100644 --- a/distro/src/main/assembly/plugin-sqoop.xml +++ b/distro/src/main/assembly/plugin-sqoop.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-trino.xml b/distro/src/main/assembly/plugin-trino.xml index 18028ba199..8c63463dc2 100644 --- a/distro/src/main/assembly/plugin-trino.xml +++ b/distro/src/main/assembly/plugin-trino.xml @@ -29,6 +29,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/plugin-yarn.xml b/distro/src/main/assembly/plugin-yarn.xml index 30534109c5..b4bab40a9c 100644 --- a/distro/src/main/assembly/plugin-yarn.xml +++ b/distro/src/main/assembly/plugin-yarn.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/ranger-tools.xml b/distro/src/main/assembly/ranger-tools.xml index 2a8f3b1784..689b239ec7 100644 --- a/distro/src/main/assembly/ranger-tools.xml +++ b/distro/src/main/assembly/ranger-tools.xml @@ -67,6 +67,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util org.apache.ranger:ranger-plugins-audit diff --git a/distro/src/main/assembly/sample-client.xml b/distro/src/main/assembly/sample-client.xml index 65b2f2071d..62cd2592aa 100644 --- a/distro/src/main/assembly/sample-client.xml +++ b/distro/src/main/assembly/sample-client.xml @@ -26,6 +26,7 @@ true + org.apache.ranger:ranger-authz-api org.apache.ranger:sample-client org.apache.ranger:ranger-intg org.apache.ranger:ranger-plugins-common diff --git a/distro/src/main/assembly/storm-agent.xml b/distro/src/main/assembly/storm-agent.xml index 8031973a20..ee375aa886 100644 --- a/distro/src/main/assembly/storm-agent.xml +++ b/distro/src/main/assembly/storm-agent.xml @@ -44,6 +44,7 @@ org.apache.ranger:ranger-audit-core org.apache.ranger:ranger-audit-dest-hdfs org.apache.ranger:ranger-audit-dest-solr + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/tagsync.xml b/distro/src/main/assembly/tagsync.xml index f3c12fe2d2..696dbaddc8 100644 --- a/distro/src/main/assembly/tagsync.xml +++ b/distro/src/main/assembly/tagsync.xml @@ -55,6 +55,7 @@ org.apache.commons:commons-compress org.apache.kafka:kafka-clients:jar:${kafka.version} org.apache.ranger:credentialbuilder + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-cred org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util diff --git a/distro/src/main/assembly/usersync.xml b/distro/src/main/assembly/usersync.xml index a15c2c3175..5e7be2bfae 100644 --- a/distro/src/main/assembly/usersync.xml +++ b/distro/src/main/assembly/usersync.xml @@ -54,6 +54,7 @@ commons-io:commons-io:jar:${commons.io.version} org.apache.httpcomponents:httpclient:jar:${httpcomponents.httpclient.version} commons-codec:commons-codec + org.apache.ranger:ranger-authz-api org.apache.ranger:ranger-plugins-common org.apache.ranger:ugsync-util org.apache.ranger:ranger-common-ha:jar:${project.version}