This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 6138a418e RANGER-5369: introduce inline-policy to support
service-managed ACLs (#743)
6138a418e is described below
commit 6138a418e882566e238e4a918aea075cf08c9e93
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Mon Dec 1 17:03:25 2025 -0800
RANGER-5369: introduce inline-policy to support service-managed ACLs (#743)
---
agents-common/pom.xml | 5 +
.../plugin/audit/RangerDefaultAuditHandler.java | 2 +-
.../ranger/plugin/model/RangerInlinePolicy.java | 178 ++++++++++++
.../ranger/plugin/model/RangerPrincipal.java | 19 ++
.../ranger/plugin/model/RangerServiceDef.java | 3 +
.../model/validation/RangerServiceDefHelper.java | 83 ++++--
.../plugin/policyengine/RangerAccessRequest.java | 6 +
.../policyengine/RangerAccessRequestImpl.java | 12 +
.../policyengine/RangerAccessRequestReadOnly.java | 7 +
.../policyengine/RangerAccessRequestWrapper.java | 6 +
.../policyengine/RangerPolicyEngineImpl.java | 20 ++
.../RangerInlinePolicyEvaluator.java | 307 +++++++++++++++++++++
.../plugin/resourcematcher/ResourceMatcher.java | 162 +++++------
.../plugin/util/RangerAccessRequestUtil.java | 20 +-
.../policyevaluator/TestInlinePolicyEvaluator.java | 145 ++++++++++
.../test_inline_policies_ozone.json | 233 ++++++++++++++++
.../authz/util/RangerResourceNameParser.java | 46 +--
.../authz/util/TestRangerResourceNameParser.java | 59 ++--
distro/src/main/assembly/admin-web.xml | 1 +
distro/src/main/assembly/hbase-agent.xml | 1 +
distro/src/main/assembly/hdfs-agent.xml | 1 +
distro/src/main/assembly/hive-agent.xml | 1 +
distro/src/main/assembly/kms.xml | 1 +
distro/src/main/assembly/knox-agent.xml | 1 +
distro/src/main/assembly/plugin-atlas.xml | 1 +
distro/src/main/assembly/plugin-elasticsearch.xml | 1 +
distro/src/main/assembly/plugin-kafka.xml | 1 +
distro/src/main/assembly/plugin-kms.xml | 1 +
distro/src/main/assembly/plugin-kylin.xml | 1 +
distro/src/main/assembly/plugin-ozone.xml | 1 +
distro/src/main/assembly/plugin-presto.xml | 1 +
distro/src/main/assembly/plugin-solr.xml | 1 +
distro/src/main/assembly/plugin-sqoop.xml | 1 +
distro/src/main/assembly/plugin-trino.xml | 1 +
distro/src/main/assembly/plugin-yarn.xml | 1 +
distro/src/main/assembly/ranger-tools.xml | 1 +
distro/src/main/assembly/sample-client.xml | 1 +
distro/src/main/assembly/storm-agent.xml | 1 +
distro/src/main/assembly/tagsync.xml | 1 +
distro/src/main/assembly/usersync.xml | 1 +
40 files changed, 1185 insertions(+), 150 deletions(-)
diff --git a/agents-common/pom.xml b/agents-common/pom.xml
index 6b82eb49f..bb2a87a19 100644
--- a/agents-common/pom.xml
+++ b/agents-common/pom.xml
@@ -160,6 +160,11 @@
<artifactId>ranger-audit-core</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger-authz-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.ranger</groupId>
<artifactId>ranger-plugin-classloader</artifactId>
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 3132a75cd..a9fb1863a 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<String> 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 000000000..d33eddbd3
--- /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<Grant> grants;
+ private String createdBy;
+ private long createTime;
+
+ public RangerInlinePolicy() {
+ this.mode = Mode.INLINE;
+ }
+
+ public RangerInlinePolicy(String grantor, Mode mode, List<Grant> 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<Grant> getGrants() {
+ return grants;
+ }
+
+ public void setGrants(List<Grant> 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<String> principals; // example: [ "u:user1, "g:group1",
"r:role1" ]; if empty, means public grant
+ private Set<String> resources; // example: [
"key:vol1/bucket1/db1/tbl1/*", "key:vol1/bucket1/db1/tbl2/*" ]; if empty, means
all resources
+ private Set<String> permissions; // example: [ "read", "write" ]; if
empty, means no permission
+
+ public Grant() {
+ }
+
+ public Grant(Set<String> principals, Set<String> resources,
Set<String> permissions) {
+ this.principals = principals;
+ this.resources = resources;
+ this.permissions = permissions;
+ }
+
+ public Set<String> getPrincipals() {
+ return principals;
+ }
+
+ public void setPrincipals(Set<String> principals) {
+ this.principals = principals;
+ }
+
+ public Set<String> getResources() {
+ return resources;
+ }
+
+ public void setResources(Set<String> resources) {
+ this.resources = resources;
+ }
+
+ public Set<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(Set<String> 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 0dc8b4201..1c3de565b 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 71a578b8f..573c485ff 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 208ba100a..18b66159f 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<String, Delegate> cache = new ConcurrentHashMap<>();
final Delegate delegate;
@@ -218,10 +223,18 @@ public Set<Set<String>> 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<String> expandImpliedAccessGrants(Set<String>
accessTypes) {
return ret;
}
+ public Map<String, String> 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<String, RangerPolicyResource>
parseResourceToPolicyResources(String resource) throws RangerAuthzException {
+ Map<String, String> 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<String> allAccessTypes;
final boolean isDataMaskSupported;
final boolean
isRowFilterSupported;
+ final char rrnResourceSepChar;
final Map<String, String> rrnTemplates = new
HashMap<>();
+ final Map<String, RangerResourceNameParser> 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<Set<String>> 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<RangerResourceDef> path = new ArrayList<>();
+ private RangerResourceNameParser createRrnParser(RangerResourceDef
resourceDef) throws RangerAuthzException {
+ List<String> 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 8b7e9b3e4..8736cb4b2 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<String, ResourceElementMatchingScope>
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 cac69d52f..29320ae09 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<String, ResourceElementMatchingScope>
resourceElementMatchingScopes = Collections.emptyMap();
+ private RangerInlinePolicy inlinePolicy;
public RangerAccessRequestImpl() {
this(null, null, null, null, null);
@@ -236,6 +238,11 @@ public Map<String, ResourceElementMatchingScope>
getResourceElementMatchingScope
return this.resourceElementMatchingScopes;
}
+ @Override
+ public RangerInlinePolicy getInlinePolicy() {
+ return inlinePolicy;
+ }
+
public void setResourceElementMatchingScopes(Map<String,
ResourceElementMatchingScope> 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 2e640d24a..0a4b8b016 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<String, ResourceElementMatchingScope>
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 5cb032d75..ffb289822 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<String, ResourceElementMatchingScope>
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 0238b7e76..e40b72e92 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<String> auditExcludedUsers;
private final Set<String> 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 000000000..8f2b319d6
--- /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<GrantEvaluator> 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<GrantEvaluator> toGrantEvaluators(RangerInlinePolicy policy) {
+ if (CollectionUtils.isEmpty(policy.getGrants())) {
+ return Collections.emptyList();
+ }
+
+ List<GrantEvaluator> 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<String> permissions;
+ private final Set<RangerPolicyResourceMatcher> 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<String, RangerPolicyResource> 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<String> userGroups;
+ private final Set<String> userRoles;
+ private final String savedUser;
+ private final Set<String> 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<String> getUserGroups() {
+ return userGroups;
+ }
+
+ @Override
+ public Set<String> 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 3462a1662..20278f46d 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<String, String> options) {
this.value = value;
@@ -55,6 +57,81 @@ abstract class ResourceMatcher {
}
}
+ abstract boolean isMatch(String resourceValue, Map<String, Object>
evalContext);
+
+ abstract boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext);
+
+ abstract boolean isChildMatch(String resourceValue, Map<String, Object>
evalContext);
+
+ abstract int getPriority();
+
+ @Override
+ public String toString() {
+ return this.getClass().getName() + "(" + this.value + ")";
+ }
+
+ final boolean isMatch(String resourceValue, ResourceElementMatchingScope
matchingScope, Map<String, Object> evalContext) {
+ final ResourceElementMatchType matchType = getMatchType(resourceValue,
matchingScope, evalContext);
+
+ return isMatch(matchType, matchingScope);
+ }
+
+ final ResourceElementMatchType getMatchType(String resourceValue,
ResourceElementMatchingScope matchingScope, Map<String, Object> 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<String, Object> 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<String> splitOnTokens(String text) {
}
}
- @Override
- public String toString() {
- return this.getClass().getName() + "(" + this.value + ")";
- }
-
- abstract boolean isMatch(String resourceValue, Map<String, Object>
evalContext);
-
- abstract boolean isPrefixMatch(String resourceValue, Map<String, Object>
evalContext);
-
- abstract boolean isChildMatch(String resourceValue, Map<String, Object>
evalContext);
-
- final boolean isMatch(String resourceValue, ResourceElementMatchingScope
matchingScope, Map<String, Object> evalContext) {
- final ResourceElementMatchType matchType = getMatchType(resourceValue,
matchingScope, evalContext);
-
- return isMatch(matchType, matchingScope);
- }
-
- final ResourceElementMatchType getMatchType(String resourceValue,
ResourceElementMatchingScope matchingScope, Map<String, Object> 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<String, Object> 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<ResourceMatcher>, 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 740425ee1..52a643ead 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<String, Object>
context, String acces
results.putIfAbsent(accessType, result);
}
}
+
+ public static String getAclEnforcerOrDefault(Map<String, Object> 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<String, Object> 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 000000000..cffdf7339
--- /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<TestData> tests;
+ }
+
+ static class TestData {
+ public String name;
+ public RangerAccessRequest request;
+ public RangerAccessResult result;
+ }
+
+ class RangerAccessRequestDeserializer implements
JsonDeserializer<RangerAccessRequest> {
+ @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<RangerAccessResource> {
+ @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 000000000..bb41f4bbd
--- /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 5000a5a43..cf789f482 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<String, 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);
@@ -202,13 +212,13 @@ public String toResourceName(Map<String, String> 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 8c137203b..06e0fe564 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<String, RangerResourceNameParser> getHiveTemplates()
throws Exception {
Map<String, RangerResourceNameParser> 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<String, RangerResourceNameParser>
getHiveTemplates() throws E
private static Map<String, RangerResourceNameParser> getS3Templates()
throws Exception {
Map<String, RangerResourceNameParser> 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<String, RangerResourceNameParser>
getS3Templates() throws Exc
private static Map<String, RangerResourceNameParser>
getAdlsGen2Templates() throws Exception {
Map<String, RangerResourceNameParser> 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<String, RangerResourceNameParser>
getAdlsGen2Templates() thro
private static Map<String, RangerResourceNameParser> getTrinoTemplates()
throws Exception {
Map<String, RangerResourceNameParser> 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<String, String> parseToMap(String resource, Map<String,
RangerResourceNameParser> 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 17a4408bb..15c0f0f62 100644
--- a/distro/src/main/assembly/admin-web.xml
+++ b/distro/src/main/assembly/admin-web.xml
@@ -235,6 +235,7 @@
<include>org.apache.tomcat:tomcat-annotations-api*</include>
<include>org.eclipse.jdt.core.compiler:ecj:jar:P20140317-1600</include>
<include>org.apache.hadoop:hadoop-auth:jar:${hadoop.version}</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
<include>org.slf4j:slf4j-api:jar:${slf4j.version}</include>
diff --git a/distro/src/main/assembly/hbase-agent.xml
b/distro/src/main/assembly/hbase-agent.xml
index 3748b371b..27cce24c9 100644
--- a/distro/src/main/assembly/hbase-agent.xml
+++ b/distro/src/main/assembly/hbase-agent.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/hdfs-agent.xml
b/distro/src/main/assembly/hdfs-agent.xml
index 8432ea895..f88500a0f 100644
--- a/distro/src/main/assembly/hdfs-agent.xml
+++ b/distro/src/main/assembly/hdfs-agent.xml
@@ -72,6 +72,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/hive-agent.xml
b/distro/src/main/assembly/hive-agent.xml
index f5f8b5bf2..b407ded85 100644
--- a/distro/src/main/assembly/hive-agent.xml
+++ b/distro/src/main/assembly/hive-agent.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/kms.xml b/distro/src/main/assembly/kms.xml
index 1aedfd9b0..1e5e7e0be 100755
--- a/distro/src/main/assembly/kms.xml
+++ b/distro/src/main/assembly/kms.xml
@@ -213,6 +213,7 @@
<include>org.apache.hadoop:hadoop-common:jar:${hadoop.version}</include>
<include>org.apache.hadoop:hadoop-auth:jar:${hadoop.version}</include>
<include>org.apache.solr:solr-solrj:jar:${solr.version}</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
<include>com.kstruct:gethostname4j:jar:${kstruct.gethostname4j.version}</include>
diff --git a/distro/src/main/assembly/knox-agent.xml
b/distro/src/main/assembly/knox-agent.xml
index d407777bf..eee995a73 100644
--- a/distro/src/main/assembly/knox-agent.xml
+++ b/distro/src/main/assembly/knox-agent.xml
@@ -45,6 +45,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-atlas.xml
b/distro/src/main/assembly/plugin-atlas.xml
index 5d6b24adc..44e18cd37 100644
--- a/distro/src/main/assembly/plugin-atlas.xml
+++ b/distro/src/main/assembly/plugin-atlas.xml
@@ -45,6 +45,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-elasticsearch.xml
b/distro/src/main/assembly/plugin-elasticsearch.xml
index 2f3f84d40..53e99622c 100644
--- a/distro/src/main/assembly/plugin-elasticsearch.xml
+++ b/distro/src/main/assembly/plugin-elasticsearch.xml
@@ -49,6 +49,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-es</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-kafka.xml
b/distro/src/main/assembly/plugin-kafka.xml
index 4db4b3ede..051cfe9ed 100644
--- a/distro/src/main/assembly/plugin-kafka.xml
+++ b/distro/src/main/assembly/plugin-kafka.xml
@@ -40,6 +40,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+
<include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-kafka-plugin</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
diff --git a/distro/src/main/assembly/plugin-kms.xml
b/distro/src/main/assembly/plugin-kms.xml
index 2d334528c..704a083b0 100755
--- a/distro/src/main/assembly/plugin-kms.xml
+++ b/distro/src/main/assembly/plugin-kms.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-kylin.xml
b/distro/src/main/assembly/plugin-kylin.xml
index 8b2b73748..be7a3de80 100644
--- a/distro/src/main/assembly/plugin-kylin.xml
+++ b/distro/src/main/assembly/plugin-kylin.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-ozone.xml
b/distro/src/main/assembly/plugin-ozone.xml
index 4a39b00d7..4c9456afb 100644
--- a/distro/src/main/assembly/plugin-ozone.xml
+++ b/distro/src/main/assembly/plugin-ozone.xml
@@ -79,6 +79,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-presto.xml
b/distro/src/main/assembly/plugin-presto.xml
index 4d6119771..d0abae771 100644
--- a/distro/src/main/assembly/plugin-presto.xml
+++ b/distro/src/main/assembly/plugin-presto.xml
@@ -56,6 +56,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-solr.xml
b/distro/src/main/assembly/plugin-solr.xml
index d1b4471a1..27cd5e597 100644
--- a/distro/src/main/assembly/plugin-solr.xml
+++ b/distro/src/main/assembly/plugin-solr.xml
@@ -39,6 +39,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-sqoop.xml
b/distro/src/main/assembly/plugin-sqoop.xml
index b1ade54bf..3e5c30f53 100644
--- a/distro/src/main/assembly/plugin-sqoop.xml
+++ b/distro/src/main/assembly/plugin-sqoop.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-trino.xml
b/distro/src/main/assembly/plugin-trino.xml
index 18028ba19..8c63463dc 100644
--- a/distro/src/main/assembly/plugin-trino.xml
+++ b/distro/src/main/assembly/plugin-trino.xml
@@ -29,6 +29,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/plugin-yarn.xml
b/distro/src/main/assembly/plugin-yarn.xml
index 30534109c..b4bab40a9 100644
--- a/distro/src/main/assembly/plugin-yarn.xml
+++ b/distro/src/main/assembly/plugin-yarn.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/ranger-tools.xml
b/distro/src/main/assembly/ranger-tools.xml
index 2a8f3b178..689b239ec 100644
--- a/distro/src/main/assembly/ranger-tools.xml
+++ b/distro/src/main/assembly/ranger-tools.xml
@@ -67,6 +67,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
<include>org.apache.ranger:ranger-plugins-audit</include>
diff --git a/distro/src/main/assembly/sample-client.xml
b/distro/src/main/assembly/sample-client.xml
index 65b2f2071..62cd2592a 100644
--- a/distro/src/main/assembly/sample-client.xml
+++ b/distro/src/main/assembly/sample-client.xml
@@ -26,6 +26,7 @@
<moduleSet>
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:sample-client</include>
<include>org.apache.ranger:ranger-intg</include>
<include>org.apache.ranger:ranger-plugins-common</include>
diff --git a/distro/src/main/assembly/storm-agent.xml
b/distro/src/main/assembly/storm-agent.xml
index 8031973a2..ee375aa88 100644
--- a/distro/src/main/assembly/storm-agent.xml
+++ b/distro/src/main/assembly/storm-agent.xml
@@ -44,6 +44,7 @@
<include>org.apache.ranger:ranger-audit-core</include>
<include>org.apache.ranger:ranger-audit-dest-hdfs</include>
<include>org.apache.ranger:ranger-audit-dest-solr</include>
+ <include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/tagsync.xml
b/distro/src/main/assembly/tagsync.xml
index f3c12fe2d..696dbaddc 100644
--- a/distro/src/main/assembly/tagsync.xml
+++ b/distro/src/main/assembly/tagsync.xml
@@ -55,6 +55,7 @@
<include>org.apache.commons:commons-compress</include>
<include>org.apache.kafka:kafka-clients:jar:${kafka.version}</include>
<include>org.apache.ranger:credentialbuilder</include>
+
<include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-cred</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
diff --git a/distro/src/main/assembly/usersync.xml
b/distro/src/main/assembly/usersync.xml
index a15c2c317..5e7be2bfa 100644
--- a/distro/src/main/assembly/usersync.xml
+++ b/distro/src/main/assembly/usersync.xml
@@ -54,6 +54,7 @@
<include>commons-io:commons-io:jar:${commons.io.version}</include>
<include>org.apache.httpcomponents:httpclient:jar:${httpcomponents.httpclient.version}</include>
<include>commons-codec:commons-codec</include>
+
<include>org.apache.ranger:ranger-authz-api</include>
<include>org.apache.ranger:ranger-plugins-common</include>
<include>org.apache.ranger:ugsync-util</include>
<include>org.apache.ranger:ranger-common-ha:jar:${project.version}</include>