You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ab...@apache.org on 2021/09/04 00:33:42 UTC

[ranger] branch ranger-2.2 updated: RANGER-3397: Update ACL computation to (optionally) expand Ranger Roles to users and groups and include chained-plugins in ACL computation

This is an automated email from the ASF dual-hosted git repository.

abhay pushed a commit to branch ranger-2.2
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/ranger-2.2 by this push:
     new 218c06f  RANGER-3397: Update ACL computation to (optionally) expand Ranger Roles to users and groups and include chained-plugins in ACL computation
218c06f is described below

commit 218c06ff54f389a2ee57d80e156ecbf7364a51ec
Author: Abhay Kulkarni <ab...@apache.org>
AuthorDate: Fri Sep 3 16:50:29 2021 -0700

    RANGER-3397: Update ACL computation to (optionally) expand Ranger Roles to users and groups and include chained-plugins in ACL computation
---
 .../plugin/policyengine/RangerPolicyEngine.java    |   2 +
 .../policyengine/RangerPolicyEngineImpl.java       |  23 ++--
 .../policyengine/RangerPolicyEngineOptions.java    |  11 +-
 .../RangerDefaultPolicyEvaluator.java              | 131 ++++++++++++++++---
 .../policyevaluator/RangerPolicyEvaluator.java     |   8 +-
 .../ranger/plugin/service/RangerBasePlugin.java    | 127 +++++++++++++++++-
 .../ranger/plugin/service/RangerChainedPlugin.java |   7 +
 .../apache/ranger/plugin/util/RangerRolesUtil.java |  64 ++++++----
 .../ranger/plugin/policyengine/TestPolicyACLs.java |  14 +-
 .../policyengine/test_aclprovider_hdfs.json        | 131 +++++++++++++++++++
 .../aclprovider/test_aclprovider_default.json      | 142 +++++++++++++++++++++
 11 files changed, 597 insertions(+), 63 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
index 7a4bb12..7bf8c7c 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
@@ -70,6 +70,8 @@ public interface RangerPolicyEngine {
 
 	RangerResourceACLs getResourceACLs(RangerAccessRequest request);
 
+	RangerResourceACLs getResourceACLs(RangerAccessRequest request, Integer requestedPolicyType);
+
 	Set<String> getRolesFromUserAndGroups(String user, Set<String> groups);
 
 	RangerRoles getRangerRoles();
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 9e0a89e..c92b550 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
@@ -243,8 +243,13 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 
 	@Override
 	public RangerResourceACLs getResourceACLs(RangerAccessRequest request) {
+		return getResourceACLs(request, null);
+	}
+
+	@Override
+	public RangerResourceACLs getResourceACLs(RangerAccessRequest request, Integer requestedPolicyType) {
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerPolicyEngineImpl.getResourceACLs(request=" + request + ")");
+			LOG.debug("==> RangerPolicyEngineImpl.getResourceACLs(request=" + request + ", policyType=" + requestedPolicyType + ")");
 		}
 
 		RangerResourceACLs ret  = new RangerResourceACLs();
@@ -269,7 +274,10 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 				LOG.debug("zoneName:[" + zoneName + "]");
 			}
 
-			for (int policyType : RangerPolicy.POLICY_TYPES) {
+			int[] policyTypes = requestedPolicyType == null ? RangerPolicy.POLICY_TYPES : new int[] { requestedPolicyType };
+
+
+			for (int policyType : policyTypes) {
 				List<RangerPolicyEvaluator> allEvaluators           = new ArrayList<>();
 				Map<Long, MatchType>        tagMatchTypeMap         = new HashMap<>();
 				Set<Long>                   policyIdForTemporalTags = new HashSet<>();
@@ -331,7 +339,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 		RangerPerfTracer.logAlways(perf);
 
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerPolicyEngineImpl.getResourceACLs(request=" + request + ") : ret=" + ret);
+			LOG.debug("<== RangerPolicyEngineImpl.getResourceACLs(request=" + request + ", policyType=" + requestedPolicyType + ") : ret=" + ret);
 		}
 
 		return ret;
@@ -773,7 +781,6 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 				if (ret.getIsAuditedDetermined() && ret.getIsAccessDetermined()) {
 					break;            // Break out of policy-evaluation loop
 				}
-
 			}
 
 			if (!ret.getIsAccessDetermined()) {
@@ -1136,6 +1143,10 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 		return ret;
 	}
 
+	private boolean getIsFallbackSupported() {
+		return policyEngine.getPluginContext().getConfig().getIsFallbackSupported();
+	}
+
 	private void updateFromPolicyACLs(RangerPolicyEvaluator evaluator, Set<Long> policyIdForTemporalTags, RangerResourceACLs resourceACLs) {
 		PolicyACLSummary aclSummary = evaluator.getPolicyACLSummary();
 
@@ -1248,10 +1259,6 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 		}
 	}
 
-	private boolean getIsFallbackSupported() {
-		return policyEngine.getPluginContext().getConfig().getIsFallbackSupported();
-	}
-
 	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/policyengine/RangerPolicyEngineOptions.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java
index 0816ec1..07d0a39 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineOptions.java
@@ -36,6 +36,7 @@ public class RangerPolicyEngineOptions {
 	public boolean enableTagEnricherWithLocalRefresher = false;
 	public boolean disableAccessEvaluationWithPolicyACLSummary = true;
 	public boolean optimizeTrieForRetrieval = false;
+	public boolean disableRoleResolution = true;
 
 	private RangerServiceDefHelper serviceDefHelper;
 
@@ -53,6 +54,7 @@ public class RangerPolicyEngineOptions {
 		this.enableTagEnricherWithLocalRefresher = other.enableTagEnricherWithLocalRefresher;
 		this.disableAccessEvaluationWithPolicyACLSummary = other.disableAccessEvaluationWithPolicyACLSummary;
 		this.optimizeTrieForRetrieval = other.optimizeTrieForRetrieval;
+		this.disableRoleResolution = other.disableRoleResolution;
 		this.serviceDefHelper = null;
 	}
 
@@ -73,6 +75,7 @@ public class RangerPolicyEngineOptions {
 		enableTagEnricherWithLocalRefresher = false;
 		disableAccessEvaluationWithPolicyACLSummary = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.access.evaluation.with.policy.acl.summary", true);
 		optimizeTrieForRetrieval = conf.getBoolean(propertyPrefix + ".policyengine.option.optimize.trie.for.retrieval", false);
+		disableRoleResolution = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.role.resolution", true);
 
 	}
 
@@ -89,6 +92,7 @@ public class RangerPolicyEngineOptions {
 		enableTagEnricherWithLocalRefresher = false;
 		disableAccessEvaluationWithPolicyACLSummary = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.access.evaluation.with.policy.acl.summary", true);
 		optimizeTrieForRetrieval = conf.getBoolean(propertyPrefix + ".policyengine.option.optimize.trie.for.retrieval", false);
+		disableRoleResolution = conf.getBoolean(propertyPrefix + ".policyengine.option.disable.role.resolution", true);
 
 	}
 
@@ -150,7 +154,8 @@ public class RangerPolicyEngineOptions {
 					&& this.cacheAuditResults == that.cacheAuditResults
 					&& this.evaluateDelegateAdminOnly == that.evaluateDelegateAdminOnly
 					&& this.enableTagEnricherWithLocalRefresher == that.enableTagEnricherWithLocalRefresher
-					&& this.optimizeTrieForRetrieval == that.optimizeTrieForRetrieval;
+					&& this.optimizeTrieForRetrieval == that.optimizeTrieForRetrieval
+					&& this.disableRoleResolution == that.disableRoleResolution;
 		}
 		return ret;
 	}
@@ -178,7 +183,8 @@ public class RangerPolicyEngineOptions {
 		ret *= 2;
 		ret += optimizeTrieForRetrieval ? 1 : 0;
 		ret *= 2;
-		return ret;
+		ret += disableRoleResolution ? 1 : 0;
+		ret *= 2;		return ret;
 	}
 
 	@Override
@@ -195,6 +201,7 @@ public class RangerPolicyEngineOptions {
 				", disableTrieLookupPrefilter: " + disableTrieLookupPrefilter +
 				", optimizeTrieForRetrieval: " + optimizeTrieForRetrieval +
 				", cacheAuditResult: " + cacheAuditResults +
+				", disableRoleResolution: " + disableRoleResolution +
 				" }";
 
 	}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
index 8c08d0e..8471918 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
@@ -81,6 +81,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 	private String perfTag;
 	private PolicyACLSummary aclSummary                 = null;
 	private boolean          useAclSummaryForEvaluation = false;
+	private boolean          disableRoleResolution      = true;
 
 	protected boolean needsDynamicEval() { return resourceMatcher != null && resourceMatcher.getNeedsDynamicEval(); }
 
@@ -160,7 +161,6 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 					allowExceptionEvaluators = Collections.<RangerPolicyItemEvaluator>emptyList();
 					denyExceptionEvaluators  = Collections.<RangerPolicyItemEvaluator>emptyList();
 				}
-
 			}
 
 			dataMaskEvaluators  = createDataMaskPolicyItemEvaluators(policy, serviceDef, options, policy.getDataMaskPolicyItems());
@@ -544,51 +544,58 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 			perf = RangerPerfTracer.getPerfTracer(PERF_POLICY_INIT_ACLSUMMARY_LOG, "RangerPolicyEvaluator.init.ACLSummary(" + perfTag + ")");
 		}
 
-		final boolean hasNonPublicGroupOrConditionsInAllowExceptions = hasNonPublicGroupOrConditions(getPolicy().getAllowExceptions());
-		final boolean hasNonPublicGroupOrConditionsInDenyExceptions  = hasNonPublicGroupOrConditions(getPolicy().getDenyExceptions());
-		final boolean hasPublicGroupInAllowAndUsersInAllowExceptions = hasPublicGroupAndUserInException(getPolicy().getPolicyItems(), getPolicy().getAllowExceptions());
-		final boolean hasPublicGroupInDenyAndUsersInDenyExceptions   = hasPublicGroupAndUserInException(getPolicy().getDenyPolicyItems(), getPolicy().getDenyExceptions());
+		RangerPolicy policy;
+		if (!disableRoleResolution && hasRoles(getPolicy())) {
+			policy = getPolicyWithRolesResolved(getPolicy());
+		} else {
+			policy = getPolicy();
+		}
+
+		final boolean hasNonPublicGroupOrConditionsInAllowExceptions = hasNonPublicGroupOrConditions(policy.getAllowExceptions());
+		final boolean hasNonPublicGroupOrConditionsInDenyExceptions  = hasNonPublicGroupOrConditions(policy.getDenyExceptions());
+		final boolean hasPublicGroupInAllowAndUsersInAllowExceptions = hasPublicGroupAndUserInException(policy.getPolicyItems(), policy.getAllowExceptions());
+		final boolean hasPublicGroupInDenyAndUsersInDenyExceptions   = hasPublicGroupAndUserInException(policy.getDenyPolicyItems(), policy.getDenyExceptions());
 		final boolean hasContextSensitiveSpecification               = hasContextSensitiveSpecification();
-		final boolean hasRoles										 = hasRoles();
+		final boolean hasRoles                                       = hasRoles(policy);
 		final boolean isUsableForEvaluation                          =    !hasNonPublicGroupOrConditionsInAllowExceptions
 		                                                               && !hasNonPublicGroupOrConditionsInDenyExceptions
 		                                                               && !hasPublicGroupInAllowAndUsersInAllowExceptions
 		                                                               && !hasPublicGroupInDenyAndUsersInDenyExceptions
-		                                                               && !hasContextSensitiveSpecification
-		                                                               && !hasRoles;
+                                                                               && !hasContextSensitiveSpecification
+                                                                               && !hasRoles;
 
 		if (isUsableForEvaluation || isCreationForced) {
 			ret = new PolicyACLSummary();
 
-			for (RangerPolicyItem policyItem : getPolicy().getDenyPolicyItems()) {
+			for (RangerPolicyItem policyItem : policy.getDenyPolicyItems()) {
 				ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY, hasNonPublicGroupOrConditionsInDenyExceptions || hasPublicGroupInDenyAndUsersInDenyExceptions);
 			}
 
 			if (!hasNonPublicGroupOrConditionsInDenyExceptions && !hasPublicGroupInDenyAndUsersInDenyExceptions) {
-				for (RangerPolicyItem policyItem : getPolicy().getDenyExceptions()) {
+				for (RangerPolicyItem policyItem : policy.getDenyExceptions()) {
 					ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS, false);
 				}
 			}
 
-			for (RangerPolicyItem policyItem : getPolicy().getPolicyItems()) {
+			for (RangerPolicyItem policyItem : policy.getPolicyItems()) {
 				ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW, hasNonPublicGroupOrConditionsInAllowExceptions || hasPublicGroupInAllowAndUsersInAllowExceptions);
 			}
 
 			if (!hasNonPublicGroupOrConditionsInAllowExceptions && !hasPublicGroupInAllowAndUsersInAllowExceptions) {
-				for (RangerPolicyItem policyItem : getPolicy().getAllowExceptions()) {
+				for (RangerPolicyItem policyItem : policy.getAllowExceptions()) {
 					ret.processPolicyItem(policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS, false);
 				}
 			}
 
-			for (RangerRowFilterPolicyItem policyItem : getPolicy().getRowFilterPolicyItems()) {
+			for (RangerRowFilterPolicyItem policyItem : policy.getRowFilterPolicyItems()) {
 				ret.processRowFilterPolicyItem(policyItem);
 			}
 
-			for (RangerDataMaskPolicyItem policyItem : getPolicy().getDataMaskPolicyItems()) {
+			for (RangerDataMaskPolicyItem policyItem : policy.getDataMaskPolicyItems()) {
 				ret.processDataMaskPolicyItem(policyItem);
 			}
 
-			final boolean isDenyAllElse = Boolean.TRUE.equals(getPolicy().getIsDenyAllElse());
+			final boolean isDenyAllElse = Boolean.TRUE.equals(policy.getIsDenyAllElse());
 
 			final Set<String> allAccessTypeNames;
 
@@ -612,6 +619,100 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		return ret;
 	}
 
+	private RangerPolicy getPolicyWithRolesResolved(final RangerPolicy policy) {
+		// Create new policy with no roles in it
+		// For each policyItem, expand roles into users and groups; and replace all policyItems with expanded roles - TBD
+
+		RangerPolicy ret = new RangerPolicy();
+		ret.updateFrom(policy);
+		ret.setId(policy.getId());
+		ret.setGuid(policy.getGuid());
+		ret.setVersion(policy.getVersion());
+
+		List<RangerPolicyItem> policyItems = new ArrayList<>();
+		List<RangerPolicyItem> denyPolicyItems = new ArrayList<>();
+		List<RangerPolicyItem> allowExceptions = new ArrayList<>();
+		List<RangerPolicyItem> denyExceptions = new ArrayList<>();
+		List<RangerDataMaskPolicyItem> dataMaskPolicyItems = new ArrayList<>();
+		List<RangerRowFilterPolicyItem> rowFilterPolicyItems = new ArrayList<>();
+
+		for (RangerPolicyItem policyItem : policy.getPolicyItems()) {
+			RangerPolicyItem newPolicyItem = new RangerPolicyItem(policyItem.getAccesses(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			policyItems.add(newPolicyItem);
+		}
+		ret.setPolicyItems(policyItems);
+
+		for (RangerPolicyItem policyItem : policy.getDenyPolicyItems()) {
+			RangerPolicyItem newPolicyItem = new RangerPolicyItem(policyItem.getAccesses(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			denyPolicyItems.add(newPolicyItem);
+		}
+		ret.setDenyPolicyItems(denyPolicyItems);
+
+		for (RangerPolicyItem policyItem : policy.getAllowExceptions()) {
+			RangerPolicyItem newPolicyItem = new RangerPolicyItem(policyItem.getAccesses(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			allowExceptions.add(newPolicyItem);
+		}
+		ret.setAllowExceptions(allowExceptions);
+
+		for (RangerPolicyItem policyItem : policy.getDenyExceptions()) {
+			RangerPolicyItem newPolicyItem = new RangerPolicyItem(policyItem.getAccesses(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			denyExceptions.add(newPolicyItem);
+		}
+		ret.setDenyExceptions(denyExceptions);
+
+		for (RangerDataMaskPolicyItem policyItem : policy.getDataMaskPolicyItems()) {
+			RangerDataMaskPolicyItem newPolicyItem = new RangerDataMaskPolicyItem(policyItem.getAccesses(), policyItem.getDataMaskInfo(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			dataMaskPolicyItems.add(newPolicyItem);
+		}
+		ret.setDataMaskPolicyItems(dataMaskPolicyItems);
+
+		for (RangerRowFilterPolicyItem policyItem : policy.getRowFilterPolicyItems()) {
+			RangerRowFilterPolicyItem newPolicyItem = new RangerRowFilterPolicyItem(policyItem.getRowFilterInfo(), policyItem.getAccesses(), policyItem.getUsers(), policyItem.getGroups(), policyItem.getRoles(), policyItem.getConditions(), policyItem.getDelegateAdmin());
+			getPolicyItemWithRolesResolved(newPolicyItem, policyItem);
+
+			rowFilterPolicyItems.add(newPolicyItem);
+		}
+		ret.setRowFilterPolicyItems(rowFilterPolicyItems);
+
+		return ret;
+	}
+
+	private void getPolicyItemWithRolesResolved(RangerPolicyItem newPolicyItem, final RangerPolicyItem policyItem) {
+		Set<String> usersFromRoles = new HashSet<>();
+		Set<String> groupsFromRoles = new HashSet<>();
+
+		List<String> roles = policyItem.getRoles();
+
+		for (String role : roles) {
+			Set<String> users = getPluginContext().getAuthContext().getRangerRolesUtil().getRoleToUserMapping().get(role);
+			Set<String> groups = getPluginContext().getAuthContext().getRangerRolesUtil().getRoleToGroupMapping().get(role);
+			if (CollectionUtils.isNotEmpty(users)) {
+				usersFromRoles.addAll(users);
+			}
+			if (CollectionUtils.isNotEmpty(groups)) {
+				groupsFromRoles.addAll(groups);
+			}
+			if (CollectionUtils.isNotEmpty(usersFromRoles) || CollectionUtils.isNotEmpty(groupsFromRoles)) {
+				usersFromRoles.addAll(policyItem.getUsers());
+				groupsFromRoles.addAll(policyItem.getGroups());
+
+				newPolicyItem.setUsers(new ArrayList<>(usersFromRoles));
+				newPolicyItem.setGroups(new ArrayList<>(groupsFromRoles));
+				newPolicyItem.setRoles(null);
+			}
+		}
+	}
+
 	private boolean hasPublicGroupAndUserInException(List<RangerPolicyItem> grants, List<RangerPolicyItem> exceptionItems) {
 		boolean ret = false;
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
index 0157c00..15a6465 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
@@ -55,8 +55,10 @@ import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatche
 
 import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW;
 import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW_EXCEPTIONS;
+import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DATAMASK;
 import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY;
 import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DENY_EXCEPTIONS;
+import static org.apache.ranger.plugin.policyevaluator.RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ROWFILTER;
 
 public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 	Comparator<RangerPolicyEvaluator> EVAL_ORDER_COMPARATOR = new RangerPolicyEvaluator.PolicyEvalOrderComparator();
@@ -140,9 +142,7 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 		return false;
 	}
 
-	default boolean hasRoles() {
-		RangerPolicy policy = getPolicy();
-
+        default boolean hasRoles(final RangerPolicy policy) {
 		for (RangerPolicyItem policyItem : policy.getPolicyItems()) {
 			if (hasRoles(policyItem)) {
 				return true;
@@ -297,7 +297,7 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 
 		void processPolicyItem(RangerPolicyItem policyItem, int policyItemType, boolean isConditional) {
 			final Integer result;
-			final boolean hasContextSensitiveSpecification = RangerPolicyEvaluator.hasContextSensitiveSpecification(policyItem);
+			final boolean hasContextSensitiveSpecification = CollectionUtils.isNotEmpty(policyItem.getConditions());
 
 			switch (policyItemType) {
 				case POLICY_ITEM_TYPE_ALLOW:
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index 7e0894d..3ad74e5 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -49,6 +49,7 @@ import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl;
 import org.apache.ranger.plugin.policyengine.RangerResourceACLs;
 import org.apache.ranger.plugin.policyengine.RangerResourceAccessInfo;
+import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
 import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
 import org.apache.ranger.plugin.util.*;
 
@@ -539,13 +540,43 @@ public class RangerBasePlugin {
 	}
 
 	public RangerResourceACLs getResourceACLs(RangerAccessRequest request) {
+		return getResourceACLs(request, null);
+	}
+
+	public RangerResourceACLs getResourceACLs(RangerAccessRequest request, Integer policyType) {
+		RangerResourceACLs ret          = null;
 		RangerPolicyEngine policyEngine = this.policyEngine;
 
 		if(policyEngine != null) {
-			return policyEngine.getResourceACLs(request);
+			ret = policyEngine.getResourceACLs(request, policyType);
 		}
 
-		return null;
+		for (RangerChainedPlugin chainedPlugin : chainedPlugins) {
+			RangerResourceACLs chainedResourceACLs = chainedPlugin.getResourceACLs(request, policyType);
+
+			if (chainedResourceACLs != null) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("Chained-plugin returned non-null ACLs!!");
+				}
+				if (chainedPlugin.isAuthorizeOnlyWithChainedPlugin()) {
+					if (LOG.isDebugEnabled()) {
+						LOG.debug("Chained-plugin is configured to ignore Base-plugin's ACLs");
+					}
+					ret = chainedResourceACLs;
+					break;
+				} else {
+					if (ret != null) {
+						ret = getMergedResourceACLs(ret, chainedResourceACLs);
+					}
+				}
+			} else {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("Chained-plugin returned null ACLs!!");
+				}
+			}
+		}
+
+		return ret;
 	}
 
 	public Set<String> getRolesFromUserAndGroups(String user, Set<String> groups) {
@@ -1035,6 +1066,98 @@ public class RangerBasePlugin {
 		}
 	}
 
+	private RangerResourceACLs getMergedResourceACLs(RangerResourceACLs baseACLs, RangerResourceACLs chainedACLs) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerBasePlugin.getMergedResourceACLs()");
+			LOG.debug("baseACLs:[" + baseACLs + "]");
+			LOG.debug("chainedACLS:[" + chainedACLs + "]");
+		}
+
+		overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.USER);
+		overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.GROUP);
+		overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.ROLE);
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerBasePlugin.getMergedResourceACLs() : ret:[" + baseACLs + "]");
+		}
+		return baseACLs;
+	}
+
+	private void overrideACLs(final RangerResourceACLs chainedResourceACLs, RangerResourceACLs baseResourceACLs, final RangerRolesUtil.ROLES_FOR userType) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerBasePlugin.overrideACLs(isUser=" + userType.name() + ")");
+		}
+		Map<String, Map<String, RangerResourceACLs.AccessResult>> chainedACLs = null;
+		Map<String, Map<String, RangerResourceACLs.AccessResult>> baseACLs    = null;
+
+		switch (userType) {
+			case USER:
+				chainedACLs = chainedResourceACLs.getUserACLs();
+				baseACLs    = baseResourceACLs.getUserACLs();
+				break;
+			case GROUP:
+				chainedACLs = chainedResourceACLs.getGroupACLs();
+				baseACLs    = baseResourceACLs.getGroupACLs();
+				break;
+			case ROLE:
+				chainedACLs = chainedResourceACLs.getRoleACLs();
+				baseACLs    = baseResourceACLs.getRoleACLs();
+				break;
+			default:
+				break;
+		}
+
+		for (Map.Entry<String, Map<String, RangerResourceACLs.AccessResult>> chainedPermissionsMap : chainedACLs.entrySet()) {
+			String                                       name               = chainedPermissionsMap.getKey();
+			Map<String, RangerResourceACLs.AccessResult> chainedPermissions = chainedPermissionsMap.getValue();
+			Map<String, RangerResourceACLs.AccessResult> basePermissions    = baseACLs.get(name);
+
+			for (Map.Entry<String, RangerResourceACLs.AccessResult> chainedPermission : chainedPermissions.entrySet()) {
+				String chainedAccessType                            = chainedPermission.getKey();
+				RangerResourceACLs.AccessResult chainedAccessResult = chainedPermission.getValue();
+				RangerResourceACLs.AccessResult baseAccessResult    = basePermissions == null ? null : basePermissions.get(chainedAccessType);
+
+				final boolean useChainedAccessResult;
+
+				if (baseAccessResult == null) {
+					useChainedAccessResult = true;
+				} else {
+					if (chainedAccessResult.getPolicy().getPolicyPriority() > baseAccessResult.getPolicy().getPolicyPriority()) {
+						useChainedAccessResult = true;
+					} else if (chainedAccessResult.getPolicy().getPolicyPriority().equals(baseAccessResult.getPolicy().getPolicyPriority())) {
+						if (chainedAccessResult.getResult() == baseAccessResult.getResult()) {
+							useChainedAccessResult = true;
+						} else {
+							useChainedAccessResult = chainedAccessResult.getResult() == RangerPolicyEvaluator.ACCESS_DENIED;
+						}
+					} else { // chainedAccessResult.getPolicy().getPolicyPriority() < baseAccessResult.getPolicy().getPolicyPriority()
+						useChainedAccessResult = false;
+					}
+				}
+
+				final RangerResourceACLs.AccessResult finalAccessResult = useChainedAccessResult ? chainedAccessResult : baseAccessResult;
+
+				switch (userType) {
+					case USER:
+						baseResourceACLs.setUserAccessInfo(name, chainedAccessType, finalAccessResult.getResult(), finalAccessResult.getPolicy());
+						break;
+					case GROUP:
+						baseResourceACLs.setGroupAccessInfo(name, chainedAccessType, finalAccessResult.getResult(), finalAccessResult.getPolicy());
+						break;
+					case ROLE:
+						baseResourceACLs.setRoleAccessInfo(name, chainedAccessType, finalAccessResult.getResult(), finalAccessResult.getPolicy());
+						break;
+					default:
+						break;
+				}
+			}
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerBasePlugin.mergeACLsOneWay(isUser=" + userType.name() + ")");
+		}
+	}
+
 	private static AuditProviderFactory getAuditProviderFactory(String serviceName) {
 		AuditProviderFactory ret = AuditProviderFactory.getInstance();
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java
index 0fca2d9..7a48a09 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerChainedPlugin.java
@@ -23,6 +23,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
 import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.plugin.policyengine.RangerResourceACLs;
 
 import java.util.Collection;
 
@@ -59,4 +60,10 @@ public abstract class RangerChainedPlugin {
 
     public abstract Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests);
 
+    public abstract RangerResourceACLs getResourceACLs(RangerAccessRequest request);
+
+    public abstract RangerResourceACLs getResourceACLs(RangerAccessRequest request, Integer policyType);
+
+    public boolean  isAuthorizeOnlyWithChainedPlugin() { return false; }
+
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
index a6e461c..f785e11 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
@@ -34,8 +34,12 @@ public class RangerRolesUtil {
     private final Map<String, Set<String>> userRoleMapping = new HashMap<>();
     private final Map<String, Set<String>> groupRoleMapping = new HashMap<>();
     private final Map<String, Set<String>> roleRoleMapping  = new HashMap<>();
+
+    private final Map<String, Set<String>> roleToUserMapping = new HashMap<>();
+    private final Map<String, Set<String>> roleToGroupMapping = new HashMap<>();
+
     private RangerRoles                    roles            = null;
-    private enum  ROLES_FOR {USER, GROUP, ROLE};
+    public  enum  ROLES_FOR {USER, GROUP, ROLE}
 
     public RangerRolesUtil(RangerRoles roles) {
         if (roles != null) {
@@ -49,7 +53,22 @@ public class RangerRolesUtil {
                     buildMap(userRoleMapping, role, containedRoles, ROLES_FOR.USER);
                     buildMap(groupRoleMapping, role, containedRoles, ROLES_FOR.GROUP);
                     buildMap(roleRoleMapping, role, containedRoles, ROLES_FOR.ROLE);
+
+                    Set<String> roleUsers  = new HashSet<>();
+                    Set<String> roleGroups = new HashSet<>();
+
+                    addMemberNames(role.getUsers(), roleUsers);
+                    addMemberNames(role.getGroups(), roleGroups);
+
+                    for (RangerRole containedRole : containedRoles) {
+                        addMemberNames(containedRole.getUsers(), roleUsers);
+                        addMemberNames(containedRole.getGroups(), roleGroups);
+                    }
+
+                    roleToUserMapping.put(role.getName(), roleUsers);
+                    roleToGroupMapping.put(role.getName(), roleGroups);
                 }
+
             }
         } else {
             roleVersion = -1L;
@@ -74,6 +93,14 @@ public class RangerRolesUtil {
         return this.roleRoleMapping;
     }
 
+    public Map<String, Set<String>> getRoleToUserMapping() {
+        return this.roleToUserMapping;
+    }
+
+    public Map<String, Set<String>> getRoleToGroupMapping() {
+        return this.roleToGroupMapping;
+    }
+
     private Set<RangerRole> getAllContainedRoles(Set<RangerRole> roles, RangerRole role) {
         Set<RangerRole> allRoles = new HashSet<>();
 
@@ -104,22 +131,6 @@ public class RangerRolesUtil {
         }
     }
 
-    private void buildMap(Map<String, Set<String>> map, RangerRole role, String roleName, boolean isUser) {
-        for (RangerRole.RoleMember userOrGroup : isUser ? role.getUsers() : role.getGroups()) {
-            if (StringUtils.isNotEmpty(userOrGroup.getName())) {
-                Set<String> roleNames = map.get(userOrGroup.getName());
-
-                if (roleNames == null) {
-                    roleNames = new HashSet<>();
-
-                    map.put(userOrGroup.getName(), roleNames);
-                }
-
-                roleNames.add(roleName);
-            }
-        }
-    }
-
     private void buildMap(Map<String, Set<String>> map, RangerRole role, String roleName, ROLES_FOR roles_for) {
         List<RangerRole.RoleMember> userOrGroupOrRole = null;
         switch(roles_for) {
@@ -141,23 +152,20 @@ public class RangerRolesUtil {
     private void getRoleMap(Map<String, Set<String>> map, String roleName, List<RangerRole.RoleMember> userOrGroupOrRole) {
         for (RangerRole.RoleMember roleMember : userOrGroupOrRole) {
             if (StringUtils.isNotEmpty(roleMember.getName())) {
-                Set<String> roleNames = map.get(roleMember.getName());
-                if (roleNames == null) {
-                    roleNames = new HashSet<>();
-
-                    map.put(roleMember.getName(), roleNames);
-                }
+                Set<String> roleNames = map.computeIfAbsent(roleMember.getName(), k -> new HashSet<>());
                 roleNames.add(roleName);
             }
         }
     }
 
     private RangerRole getContainedRole(Set<RangerRole> roles, String role) {
-        return (roles
-                .stream()
-                .filter(containedRole -> role.equals(containedRole.getName()))
-                .findAny()
-                .orElse(null));
+        return (roles.stream().filter(containedRole -> role.equals(containedRole.getName())).findAny().orElse(null));
+    }
+
+    private void addMemberNames(List<RangerRole.RoleMember> members, Set<String> names) {
+        for (RangerRole.RoleMember member : members) {
+            names.add(member.getName());
+        }
     }
 }
 
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
index d2983a2..b6135b0 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
@@ -86,6 +86,13 @@ public class TestPolicyACLs {
 		runTestsFromResourceFiles(tests);
 	}
 
+	@Test
+	public void testResourceACLs_hdfs() throws Exception {
+		String[] tests = {"/policyengine/test_aclprovider_hdfs.json"};
+
+		runTestsFromResourceFiles(tests);
+	}
+
 	private void runTestsFromResourceFiles(String[] resourceNames) throws Exception {
 		for(String resourceName : resourceNames) {
 			InputStream       inStream = this.getClass().getResourceAsStream(resourceName);
@@ -101,8 +108,9 @@ public class TestPolicyACLs {
 		assertTrue("invalid input: " + testName, testCases != null && testCases.testCases != null);
 
 		for(PolicyACLsTests.TestCase testCase : testCases.testCases) {
+			String                    serviceType         = testCase.servicePolicies.getServiceDef().getName();
 			RangerPolicyEngineOptions policyEngineOptions = new RangerPolicyEngineOptions();
-			RangerPluginContext       pluginContext       = new RangerPluginContext(new RangerPluginConfig("hive", null, "test-policy-acls", "cl1", "on-prem", policyEngineOptions));
+			RangerPluginContext       pluginContext       = new RangerPluginContext(new RangerPluginConfig(serviceType, null, "test-policy-acls", "cl1", "on-prem", policyEngineOptions));
 			RangerPolicyEngine        policyEngine        = new RangerPolicyEngineImpl(testCase.servicePolicies, pluginContext, null);
 
 			for(PolicyACLsTests.TestCase.OneTest oneTest : testCase.tests) {
@@ -259,9 +267,7 @@ public class TestPolicyACLs {
 				} else if (!(MapUtils.isEmpty(acls.getRoleACLs()) && MapUtils.isEmpty(oneTest.rolePermissions))) {
 					roleACLsMatched = false;
 				}
-
-				assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name + " - userACLsMatched=" + userACLsMatched + "; groupACLsMatched=" + groupACLsMatched + "; roleACLsMatched=" + roleACLsMatched + "; rowFiltersMatched=" + rowFiltersMatched + "; dataMaskingMatched=" + dataMaskingMatched,
-						   userACLsMatched && groupACLsMatched && roleACLsMatched && rowFiltersMatched && dataMaskingMatched);
+				assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name, userACLsMatched && groupACLsMatched && roleACLsMatched && rowFiltersMatched && dataMaskingMatched);
 			}
 		}
 	}
diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json b/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json
new file mode 100644
index 0000000..9526763
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_aclprovider_hdfs.json
@@ -0,0 +1,131 @@
+{
+  "testCases": [
+    {
+      "name": "Test-ACL-Provider-for-HDFS",
+
+      "servicePolicies": {
+        "serviceName": "hivedev",
+        "serviceDef": {
+          "name": "hdfs",
+          "id": 1,
+          "resources": [
+            {
+              "name": "path",
+              "type": "path",
+              "level": 1,
+              "mandatory": true,
+              "lookupSupported": true,
+              "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",
+              "matcherOptions": {
+                "wildCard": true,
+                "ignoreCase": true
+              },
+              "label": "Resource Path",
+              "description": "HDFS file or directory path"
+            }
+          ],
+          "accessTypes": [
+            {
+              "name": "read",
+              "label": "Read"
+            },
+            {
+              "name": "write",
+              "label": "Write"
+            },
+            {
+              "name": "execute",
+              "label": "Execute"
+            }
+          ],
+          "contextEnrichers": [
+            {
+              "itemId": 1,
+              "name": "GeolocationEnricher",
+              "enricher": "org.apache.ranger.plugin.contextenricher.RangerFileBasedGeolocationProvider",
+              "enricherOptions": {
+                "FilePath": "/etc/ranger/geo/geo.txt",
+                "ForceRead": "false",
+                "IPInDotFormat": "true",
+                "geolocation.meta.prefix": "TEST_"
+              }
+            }
+          ],
+          "policyConditions": [
+            {
+              "itemId": 1,
+              "name": "ScriptConditionEvaluator",
+              "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator",
+              "evaluatorOptions": {
+                "engineName": "JavaScript"
+              },
+              "label": "Script",
+              "description": "Script to execute"
+            }
+          ]
+        },
+        "policies": [
+          {
+            "id": 1, "name": "audit-all-access under /finance/restricted/",
+            "resources": {
+              "path": {"values": ["/finance/restricted/"], "isRecursive": true}
+            },
+            "policyItems": [
+              {"accesses": [], "users": [], "groups": [ "public"]}
+            ]
+          },
+          {
+            "id": 2, "name": "allow-read-to-all under /public/",
+            "resources": {
+              "path": {"values": [ "/public/*" ], "isRecursive": true}
+            },
+            "policyItems": [
+              {"accesses": [{"type": "read", "isAllowed": true},{"type": "execute", "isAllowed": true}], "users": [], "groups": ["public"]}
+            ]
+          },
+          {
+            "id": 3, "name": "allow-read-to-finance under /finance/restricted",
+            "resources": {
+              "path": {"values": [ "/finance/restricted" ], "isRecursive": true}
+            },
+            "policyItems": [
+              {"accesses": [{"type": "read", "isAllowed": true}], "users": [], "groups": ["finance"]}
+            ]
+          },
+          {
+            "id": 4, "name": "allow-read-to-finance under /finance/limited",
+            "resources": {
+              "path": {"values": [ "/finance/limited"], "isRecursive": true}
+            },
+            "policyItems": [
+              {"accesses": [{"type": "read", "isAllowed": true}], "users": [], "groups": ["stewards"]}
+            ]
+          }
+        ]
+      },
+      "tests": [
+        {
+          "name": "test-finance-restricted",
+          "resource": {"elements":{"path":"/finance/restricted"}},
+          "userPermissions": {},
+          "groupPermissions": {"finance": {"read": {"result": 1, "isFinal": true}}},
+          "rolePermissions": {}
+        },
+        {
+          "name": "test-finance-limited",
+          "resource": {"elements":{"path":"/finance/limited"}},
+          "userPermissions": {},
+          "groupPermissions": {"stewards": {"read": {"result": 1, "isFinal": true}}},
+          "rolePermissions": {}
+        },
+        {
+          "name": "test-anything-under-public",
+          "resource": {"elements":{"path":"/public/anything"}},
+          "userPermissions": {},
+          "groupPermissions": {"public": {"read": {"result": 1, "isFinal": true}, "execute": {"result": 1, "isFinal": true}}},
+          "rolePermissions": {}
+        }
+      ]
+    }
+  ]
+}
diff --git a/hdfs-agent/src/test/resources/aclprovider/test_aclprovider_default.json b/hdfs-agent/src/test/resources/aclprovider/test_aclprovider_default.json
new file mode 100644
index 0000000..c345ec6
--- /dev/null
+++ b/hdfs-agent/src/test/resources/aclprovider/test_aclprovider_default.json
@@ -0,0 +1,142 @@
+{
+  "testCases": [
+    {
+      "name": "Test-ACL-Provider",
+      "roles" : { "serviceName":  "hdfsdev", "roleVersion": 1,
+        "rangerRoles": [ { "name":  "admin", "users":  [{"name":"admin-1","isAdmin": false}, {"name":"admin-2", "isAdmin": false}], "groups" : [{"name":"admin-group-1", "isAdmin":false}, {"name":"admin-group-2", "isAdmin": false}], "roles": [{"name": "sub-admin-1","isAdmin":false}, {"name":"sub-admin-2", "isAdmin": false}] },
+          { "name":  "sub-admin-1", "users":  [{"name":"sub-admin-user-1", "isAdmin": false}], "groups" : [], "roles": [] },
+          { "name":  "sub-admin-2", "users":  [], "groups" : [{"name":"sub-admin-group-2", "isAdmin":false}], "roles": [] }
+        ]
+      },
+      "servicePolicies": {
+        "serviceName": "hdfsdev",
+        "serviceDef": {
+          "name": "hdfs", "id": 1,
+          "resources": [
+            {"name": "path", "type": "path", "level": 1, "mandatory": true, "lookupSupported": true,
+              "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher",
+              "matcherOptions": {"wildCard": true, "ignoreCase": true},
+              "label": "Resource Path", "description": "HDFS file or directory path"
+            }
+          ],
+          "accessTypes": [
+            {"name": "read", "label": "Read"},
+            {"name": "write", "label": "Write"},
+            {"name": "execute", "label": "Execute"}
+          ],
+          "contextEnrichers": [
+            {
+              "itemId": 1,
+              "name": "GeolocationEnricher",
+              "enricher": "org.apache.ranger.plugin.contextenricher.RangerFileBasedGeolocationProvider",
+              "enricherOptions": {"FilePath": "/etc/ranger/geo/geo.txt", "ForceRead": "false", "IPInDotFormat": "true", "geolocation.meta.prefix": "TEST_"}
+            }
+          ],
+          "policyConditions": [
+            {
+              "itemId": 1,
+              "name": "ScriptConditionEvaluator",
+              "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator",
+              "evaluatorOptions": {"engineName": "JavaScript"},
+              "label": "Script",
+              "description": "Script to execute"
+            }
+          ]
+        },
+        "serviceConfig": {"ranger.plugin.hdfs.chained.service" :  "mapped_hive", "ranger.plugin.hdfs.chained.service.mapped_hive.impl": "org.apache.ranger.chainedplugin.hdfs.hive.RangerHdfsHiveChainedPlugin"},
+        "policies": [
+          {
+            "id": 10,
+            "name": "allow-read-to-user1,user3 /test/restricted",
+            "isEnabled": true, "isAuditEnabled": true, "isDenyAllElse": true,
+            "resources": {"path": {"values": ["/test/restricted"], "isRecursive": true}},
+            "policyItems": [
+              { "accesses": [{"type": "read", "isAllowed": true}], "users": ["user1", "user2", "user3"], "groups": [], "roles":["sub-admin-1"],"delegateAdmin": false }
+            ],
+            "allowExceptions": [
+              { "accesses": [{"type": "read", "isAllowed": true}], "users": ["user2"], "groups": [], "delegateAdmin": false }
+            ]
+          },
+          {
+            "id": 20,
+            "name": "allow-read-to-user2 /test/restricted/a",
+            "isEnabled": true, "isAuditEnabled": true,
+            "resources": {"path": {"values": ["/test/restricted/a"],"isRecursive": true}},
+            "policyItems": [
+              { "accesses": [ {"type": "read", "isAllowed": true}, {"type": "write", "isAllowed": true} ], "users": ["user2", "non-user1", "non-user2", "non-user3"], "groups": ["public"], "delegateAdmin": false }
+            ],
+            "denyPolicyItems": [
+              { "accesses": [ {"type": "read", "isAllowed": true} ], "users": ["non-user4"], "groups": [], "delegateAdmin": false }
+            ]
+          },
+          {
+            "id": 30,
+            "name": "deny-read-to-user3 /test/restricted/b",
+            "isEnabled": true, "isAuditEnabled": true,
+            "resources": {"path": {"values": ["/test/restricted/b"], "isRecursive": true} },
+            "policyItems": [
+              { "accesses": [ {"type": "read", "isAllowed": true} ], "users": ["non-user5", "non-user6", "non-user7", "non-user8"], "groups": ["public"], "delegateAdmin": false, "conditions": [ { "type": "ScriptConditionEvaluator", "values": [ "var country_code = ctx.getRequestContextAttribute('LOCATION_TEST_COUNTRY_CODE'); ctx.result = !!country_code;" ] } ] }
+            ],
+            "denyPolicyItems": [
+              { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [ "user3", "non-user9" ], "groups": [], "delegateAdmin": false }
+            ]
+          },
+          {
+            "id": 1,
+            "name": "audit-all-access under /finance/restricted",
+            "isEnabled": true, "isAuditEnabled": true,
+            "resources": { "path": { "values": [ "/finance/restricted" ], "isRecursive": true } },
+            "policyItems": [
+              { "accesses": [], "users": [], "groups": [ "public" ], "delegateAdmin": false }
+            ]
+          },
+          {
+            "id": 2,
+            "name": "allow-read-to-all under /public/*",
+            "isEnabled": true, "isAuditEnabled": false,
+            "resources": { "path": { "values": [ "/public/*" ], "isRecursive": true } },
+            "policyItems": [
+              { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "execute", "isAllowed": true } ], "users": [], "groups": [ "public" ], "delegateAdmin": false }
+            ]
+          },
+          {
+            "id": 3,
+            "name": "allow-read-to-finance under /finance/restricted",
+            "isEnabled": true, "isAuditEnabled": true,
+            "resources": { "path": { "values": [ "/finance/restricted" ], "isRecursive": true } },
+            "policyItems": [
+              { "accesses": [ { "type": "read", "isAllowed": true } ], "users": [], "groups": [ "finance" ], "delegateAdmin": false, "conditions": [ { "type": "ScriptConditionEvaluator", "values": [ "var country_code = ctx.getRequestContextAttribute('LOCATION_TEST_COUNTRY_CODE'); ctx.result = !!country_code;" ] } ] }
+            ]
+          },
+          {
+            "id": 4,
+            "name": "No access for /forbidden",
+            "isEnabled": true, "isAuditEnabled": true,
+            "isDenyAllElse": true,
+            "resources": { "path": { "values": [ "/forbidden" ], "isRecursive": true } },
+            "policyItems": [
+              { "accesses": [ { "type": "read", "isAllowed": true }, { "type": "read", "isAllowed": true }, { "type": "write", "isAllowed": true },{ "type": "execute", "isAllowed": true } ], "users": [], "groups": [ "public" ], "delegateAdmin": false }
+            ]
+          }
+        ]
+      }
+    ,
+      "tests": [
+        {
+          "name": "/test/restricted access",
+          "resource": {"elements":{"path":"/test/restricted" }},
+          "userPermissions": {"user1": {"read": {"result":-1, "isFinal" : true}, "write": {"result":-1,"isFinal":true}, "execute":{"result":-1, "isFinal": true}}, "user2": {"read": {"result":-1, "isFinal" : true}, "write": {"result":-1,"isFinal":true}, "execute":{"result":-1, "isFinal": true}},"user3": {"read": {"result":0, "isFinal" : true}, "write": {"result":0,"isFinal":true}, "execute":{"result":0, "isFinal": true}}, "sub-admin-user-1": {"read": {"result":1, "isFinal" : true}, "write [...]
+          "groupPermissions": {"public": {"read": {"result":2, "isFinal" : true},"write": {"result":-1,"isFinal":true}, "execute":{"result":-1, "isFinal": true}}}
+        },
+        {
+          "name": "all-deny-test",
+          "resource": {"elements":{"path":"/forbidden" }},
+          "userPermissions": {},
+          "groupPermissions": {"public": {"read": {"result":1, "isFinal" : true},"write": {"result":1,"isFinal":true}, "execute":{"result":1, "isFinal": true}},
+            "other": {"read": {"result":-1, "isFinal" : true},"write": {"result":-1,"isFinal":true}, "execute":{"result":-1, "isFinal": true}}}
+        }
+      ]
+    }
+  ]
+}
+