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}