This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch RANGER-3923 in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/RANGER-3923 by this push: new 87bec2676 RANGER-4269: gds policy engine implementation of getResourceACLs() API - #3 87bec2676 is described below commit 87bec2676f06d0da9d37f710fd23c0b6b7f031f2 Author: Madhan Neethiraj <mad...@apache.org> AuthorDate: Wed Nov 8 19:22:24 2023 -0800 RANGER-4269: gds policy engine implementation of getResourceACLs() API - #3 --- .../policyengine/RangerPolicyEngineImpl.java | 2 +- .../plugin/policyengine/RangerResourceACLs.java | 43 +++++++ .../policyengine/gds/GdsDataShareEvaluator.java | 37 ++++++ .../policyengine/gds/GdsDatasetEvaluator.java | 16 +++ .../plugin/policyengine/gds/GdsDipEvaluator.java | 27 ++++ .../plugin/policyengine/gds/GdsDshidEvaluator.java | 28 ++++- .../plugin/policyengine/gds/GdsPolicyEngine.java | 19 +++ .../policyengine/gds/GdsProjectEvaluator.java | 14 +++ .../gds/GdsSharedResourceEvaluator.java | 21 ++++ .../RangerAbstractPolicyEvaluator.java | 46 +++++-- .../policyevaluator/RangerPolicyEvaluator.java | 2 +- .../ranger/plugin/service/RangerBasePlugin.java | 42 +++++++ .../policyengine/gds/TestGdsPolicyEngine.java | 13 +- .../gds/test_gds_policy_engine_hive.json | 139 +++++++++++++++++++-- 14 files changed, 427 insertions(+), 22 deletions(-) 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 e268fff38..2d576c580 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 @@ -317,7 +317,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine { boolean isTemporalTagPolicy = policyIdForTemporalTags.contains(evaluator.getPolicyId()); MatchType tagMatchType = tagMatchTypeMap.get(evaluator.getPolicyId()); - evaluator.getResourceACLs(request, ret, isTemporalTagPolicy, tagMatchType, policyEngine); + evaluator.getResourceACLs(request, ret, isTemporalTagPolicy, null, tagMatchType, policyEngine); } ret.finalizeAcls(); diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java index f8554d574..694bebdcf 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java @@ -31,6 +31,7 @@ import org.codehaus.jackson.map.annotate.JsonSerialize; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -46,6 +47,8 @@ public class RangerResourceACLs { final private Map<String, Map<String, AccessResult>> roleACLs = new HashMap<>(); final private List<RowFilterResult> rowFilters = new ArrayList<>(); final private List<DataMaskResult> dataMasks = new ArrayList<>(); + final private Set<String> datasets = new HashSet<>(); + final private Set<String> projects = new HashSet<>(); public RangerResourceACLs() { } @@ -64,6 +67,10 @@ public class RangerResourceACLs { public List<DataMaskResult> getDataMasks() { return dataMasks; } + public Set<String> getDatasets() { return datasets; } + + public Set<String> getProjects() { return projects; } + public void finalizeAcls() { Map<String, AccessResult> publicGroupAccessInfo = groupACLs.get(RangerPolicyEngine.GROUP_PUBLIC); if (publicGroupAccessInfo != null) { @@ -162,6 +169,30 @@ public class RangerResourceACLs { } } + @Override + public int hashCode() { + return Objects.hash(userACLs, groupACLs, roleACLs, rowFilters, dataMasks); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } else { + RangerResourceACLs other = (RangerResourceACLs) obj; + + return Objects.equals(userACLs, other.userACLs) && + Objects.equals(groupACLs, other.groupACLs) && + Objects.equals(roleACLs, other.roleACLs) && + Objects.equals(rowFilters, other.rowFilters) && + Objects.equals(dataMasks, other.dataMasks) && + Objects.equals(datasets, other.datasets) && + Objects.equals(projects, other.projects); + } + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -220,6 +251,18 @@ public class RangerResourceACLs { } sb.append("]"); + sb.append(", datasets=["); + for (String dataset : datasets) { + sb.append(dataset).append(" "); + } + sb.append("]"); + + sb.append(", projects=["); + for (String project : projects) { + sb.append(project).append(" "); + } + sb.append("]"); + return sb.toString(); } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java index 83ab59630..4936a86ed 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDataShareEvaluator.java @@ -24,6 +24,7 @@ import org.apache.ranger.plugin.conditionevaluator.RangerConditionEvaluator; import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.policyengine.RangerResourceTrie; import org.apache.ranger.plugin.policyevaluator.RangerCustomConditionEvaluator; import org.apache.ranger.plugin.util.RangerResourceEvaluatorsRetriever; @@ -140,6 +141,42 @@ public class GdsDataShareEvaluator { LOG.debug("<== GdsDataShareEvaluator.evaluate({}, {})", request, result); } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, Map<Long, GdsDatasetEvaluator> datasets, Map<Long, GdsProjectEvaluator> projects) { + LOG.debug("==> GdsDataShareEvaluator.getResourceACLs({}, {})", request, acls); + + List<GdsSharedResourceEvaluator> evaluators = getResourceEvaluators(request); + + if (!evaluators.isEmpty()) { + boolean isConditional = conditionEvaluator != null; + + for (GdsSharedResourceEvaluator evaluator : evaluators) { + evaluator.getResourceACLs(request, acls, isConditional, dsidEvaluators, datasets, projects); + } + } + + LOG.debug("<== GdsDataShareEvaluator.getResourceACLs({}, {})", request, acls); + } + + private List<GdsSharedResourceEvaluator> getResourceEvaluators(RangerAccessRequest request) { + final List<GdsSharedResourceEvaluator> ret; + + Collection<GdsSharedResourceEvaluator> evaluators = RangerResourceEvaluatorsRetriever.getEvaluators(resourceTries, request.getResource().getAsMap(), request.getResourceElementMatchingScopes()); + + if (evaluators == null) { + ret = Collections.emptyList(); + } else if (evaluators.size() > 1) { + ret = new ArrayList<>(evaluators); + + ret.sort(GdsSharedResourceEvaluator.EVAL_ORDER_COMPARATOR); + } else { + ret = Collections.singletonList(evaluators.iterator().next()); + } + + LOG.debug("GdsDataShareEvaluator.getResourceEvaluators({}): found {} evaluators", request, ret.size()); + + return ret; + } + public static class GdsDataShareEvalOrderComparator implements Comparator<GdsDataShareEvaluator> { @Override public int compare(GdsDataShareEvaluator me, GdsDataShareEvaluator other) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java index 61047134b..aa9fbea7c 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDatasetEvaluator.java @@ -25,6 +25,7 @@ import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.policyengine.*; import org.apache.ranger.plugin.policyevaluator.RangerOptimizedPolicyEvaluator; import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; +import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; import org.apache.ranger.plugin.util.ServiceGdsInfo.DatasetInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -117,6 +118,21 @@ public class GdsDatasetEvaluator { LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {})", request, result); } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set<String> allowedAccessTypes, Map<Long, GdsProjectEvaluator> projects) { + acls.getDatasets().add(getName()); + + if (!policyEvaluators.isEmpty()) { + GdsDatasetAccessRequest datasetRequest = new GdsDatasetAccessRequest(getId(), gdsServiceDef, request); + + for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { + policyEvaluator.getResourceACLs(datasetRequest, acls, isConditional, allowedAccessTypes, RangerPolicyResourceMatcher.MatchType.SELF, null); + } + } + + for (GdsDipEvaluator dipEvaluator : dipEvaluators) { + dipEvaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes, projects); + } + } public static class GdsDatasetAccessRequest extends RangerAccessRequestImpl { public GdsDatasetAccessRequest(Long datasetId, RangerServiceDef gdsServiceDef, RangerAccessRequest request) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java index 2198eadf1..a5256ca4c 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDipEvaluator.java @@ -21,10 +21,18 @@ package org.apache.ranger.plugin.policyengine.gds; import org.apache.ranger.plugin.model.RangerGds; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator; import org.apache.ranger.plugin.util.ServiceGdsInfo.DatasetInProjectInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Set; public class GdsDipEvaluator { + private static final Logger LOG = LoggerFactory.getLogger(GdsDipEvaluator.class); + private final DatasetInProjectInfo dip; private final RangerValidityScheduleEvaluator scheduleEvaluator; @@ -57,6 +65,25 @@ public class GdsDipEvaluator { } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set<String> allowedAccessTypes, Map<Long, GdsProjectEvaluator> projects) { + LOG.debug("==> GdsDipEvaluator.getResourceACLs({}, {})", request, acls); + + if (dip.getStatus() == RangerGds.GdsShareStatus.ACTIVE) { + GdsProjectEvaluator evaluator = projects.get(dip.getProjectId()); + + if (evaluator != null) { + isConditional = isConditional || scheduleEvaluator != null; + + evaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes); + } else { + LOG.warn("GdsDipEvaluator.getResourceACLs({}): evaluator for projectId={} not found", request, dip.getProjectId()); + } + } + + LOG.debug("<== GdsDipEvaluator.getResourceACLs({}, {})", request, acls); + } + + private boolean isActive() { boolean ret = dip.getStatus() == RangerGds.GdsShareStatus.ACTIVE; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java index 97bb06b2e..c32f22b27 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsDshidEvaluator.java @@ -21,11 +21,19 @@ package org.apache.ranger.plugin.policyengine.gds; import org.apache.ranger.plugin.model.RangerGds; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator; import org.apache.ranger.plugin.util.ServiceGdsInfo.DataShareInDatasetInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Set; public class GdsDshidEvaluator { - private final DataShareInDatasetInfo dshid; + private static final Logger LOG = LoggerFactory.getLogger(GdsDshidEvaluator.class); + + private final DataShareInDatasetInfo dshid; private final RangerValidityScheduleEvaluator scheduleEvaluator; public GdsDshidEvaluator(DataShareInDatasetInfo dshid) { @@ -56,6 +64,24 @@ public class GdsDshidEvaluator { return ret; } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Map<Long, GdsDatasetEvaluator> datasets, Map<Long, GdsProjectEvaluator> projects, Set<String> allowedAccessTypes) { + LOG.debug("==> GdsDshidEvaluator.getResourceACLs({}, {})", request, acls); + + if (dshid.getStatus() == RangerGds.GdsShareStatus.ACTIVE) { + GdsDatasetEvaluator datasetEvaluator = datasets.get(dshid.getDatasetId()); + + if (datasetEvaluator != null) { + isConditional = isConditional || scheduleEvaluator != null; + + datasetEvaluator.getResourceACLs(request, acls, isConditional, allowedAccessTypes, projects); + } else { + LOG.warn("GdsDshidEvaluator.getResourceACLs({}): datasetEvaluator for datasetId={} not found", request, dshid.getDatasetId()); + } + } + + LOG.debug("<== GdsDshidEvaluator.getResourceACLs({}, {})", request, acls); + } + private boolean isActive() { boolean ret = dshid.getStatus() == RangerGds.GdsShareStatus.ACTIVE; diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java index 809bbfa96..d9aa81732 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java @@ -27,6 +27,7 @@ import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerPluginContext; import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.ServiceGdsInfo; import org.apache.ranger.plugin.util.ServiceGdsInfo.DatasetInfo; @@ -98,6 +99,24 @@ public class GdsPolicyEngine { return ret; } + public RangerResourceACLs getResourceACLs(RangerAccessRequest request) { + RangerResourceACLs ret = new RangerResourceACLs(); + + List<GdsDataShareEvaluator> dataShares = getDataShareEvaluators(request); + + if (!dataShares.isEmpty()) { + if (dataShares.size() > 1) { + dataShares.sort(GdsDataShareEvaluator.EVAL_ORDER_COMPARATOR); + } + + for (GdsDataShareEvaluator dshEvaluator : dataShares) { + dshEvaluator.getResourceACLs(request, ret, datasets, projects); + } + } + + return ret; + } + private void init(RangerServiceDefHelper serviceDefHelper, RangerPluginContext pluginContext) { LOG.debug("==> RangerGdsPolicyEngine.init()"); diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java index 446f2a90a..17a86163b 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsProjectEvaluator.java @@ -25,6 +25,7 @@ import org.apache.ranger.plugin.model.RangerServiceDef; import org.apache.ranger.plugin.policyengine.*; import org.apache.ranger.plugin.policyevaluator.RangerOptimizedPolicyEvaluator; import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; +import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; import org.apache.ranger.plugin.util.ServiceGdsInfo.ProjectInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Set; public class GdsProjectEvaluator { private static final Logger LOG = LoggerFactory.getLogger(GdsDatasetEvaluator.class); @@ -105,6 +107,18 @@ public class GdsProjectEvaluator { LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {})", request, result); } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set<String> allowedAccessTypes) { + acls.getProjects().add(getName()); + + if (!policyEvaluators.isEmpty()) { + GdsProjectAccessRequest projectRequest = new GdsProjectAccessRequest(getId(), gdsServiceDef, request); + + for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { + policyEvaluator.getResourceACLs(projectRequest, acls, isConditional, allowedAccessTypes, RangerPolicyResourceMatcher.MatchType.SELF, null); + } + } + } + public static class GdsProjectAccessRequest extends RangerAccessRequestImpl { public GdsProjectAccessRequest(Long projectId, RangerServiceDef gdsServiceDef, RangerAccessRequest request) { diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java index 33a9e44fa..726331271 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsSharedResourceEvaluator.java @@ -29,6 +29,7 @@ import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; import org.apache.ranger.plugin.policyevaluator.RangerCustomConditionEvaluator; import org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; @@ -106,6 +107,10 @@ public class GdsSharedResourceEvaluator implements RangerResourceEvaluator { return resource != null && resource.getResource() != null ? resource.getResource().keySet() : Collections.emptySet(); } + public boolean isConditional() { return conditionEvaluator != null; } + + public Set<String> getAllowedAccessTypes() { return allowedAccessTypes; } + public boolean isAllowed(RangerAccessRequest request) { LOG.debug("==> GdsSharedResourceEvaluator.evaluate({})", request); @@ -132,6 +137,22 @@ public class GdsSharedResourceEvaluator implements RangerResourceEvaluator { return ret; } + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, List<GdsDshidEvaluator> dshidEvaluators, Map<Long, GdsDatasetEvaluator> datasets, Map<Long, GdsProjectEvaluator> projects) { + LOG.debug("==> GdsSharedResourceEvaluator.getResourceACLs({}, {})", request, acls); + + boolean isResourceMatch = policyResourceMatcher.isMatch(request.getResource(), request.getResourceElementMatchingScopes(), request.getContext()); + + if (isResourceMatch) { + isConditional = isConditional || conditionEvaluator != null; + + for (GdsDshidEvaluator dshidEvaluator : dshidEvaluators) { + dshidEvaluator.getResourceACLs(request, acls, isConditional, datasets, projects, getAllowedAccessTypes()); + } + } + + LOG.debug("<== GdsSharedResourceEvaluator.getResourceACLs({}, {})", request, acls); + } + public RangerPolicyItemRowFilterInfo getRowFilter() { return resource.getRowFilter(); } diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java index b60fc9fb1..07fe6a38d 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java @@ -154,7 +154,7 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu } @Override - public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, MatchType matchType, PolicyEngine policyEngine) { + public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set<String> targetAccessTypes, MatchType matchType, PolicyEngine policyEngine) { boolean isMatched = false; boolean isConditionalMatch = false; @@ -186,11 +186,11 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu int policyType = getPolicyType(); if (policyType == RangerPolicy.POLICY_TYPE_ACCESS) { - updateFromPolicyACLs(isConditionalMatch, acls); + updateFromPolicyACLs(isConditionalMatch, acls, targetAccessTypes); } else if (policyType == RangerPolicy.POLICY_TYPE_ROWFILTER) { - updateRowFiltersFromPolicy(isConditionalMatch, acls); + updateRowFiltersFromPolicy(isConditionalMatch, acls, targetAccessTypes); } else if (policyType == RangerPolicy.POLICY_TYPE_DATAMASK) { - updateDataMasksFromPolicy(isConditionalMatch, acls); + updateDataMasksFromPolicy(isConditionalMatch, acls, targetAccessTypes); } } } @@ -317,7 +317,7 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu } - private void updateFromPolicyACLs(boolean isConditional, RangerResourceACLs resourceACLs) { + private void updateFromPolicyACLs(boolean isConditional, RangerResourceACLs resourceACLs, Set<String> targetAccessTypes) { PolicyACLSummary aclSummary = getPolicyACLSummary(); if (aclSummary == null) { @@ -328,6 +328,12 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu final String userName = userAccessInfo.getKey(); for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : userAccessInfo.getValue().entrySet()) { + String accessType = accessInfo.getKey(); + + if (targetAccessTypes != null && !targetAccessTypes.contains(accessType)) { + continue; + } + Integer accessResult; if (isConditional) { @@ -342,7 +348,7 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu RangerPolicy policy = getPolicy(); - resourceACLs.setUserAccessInfo(userName, accessInfo.getKey(), accessResult, policy); + resourceACLs.setUserAccessInfo(userName, accessType, accessResult, policy); } } @@ -350,6 +356,12 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu final String groupName = groupAccessInfo.getKey(); for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : groupAccessInfo.getValue().entrySet()) { + String accessType = accessInfo.getKey(); + + if (targetAccessTypes != null && !targetAccessTypes.contains(accessType)) { + continue; + } + Integer accessResult; if (isConditional) { @@ -364,7 +376,7 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu RangerPolicy policy = getPolicy(); - resourceACLs.setGroupAccessInfo(groupName, accessInfo.getKey(), accessResult, policy); + resourceACLs.setGroupAccessInfo(groupName, accessType, accessResult, policy); } } @@ -372,6 +384,12 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu final String roleName = roleAccessInfo.getKey(); for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : roleAccessInfo.getValue().entrySet()) { + String accessType = accessInfo.getKey(); + + if (targetAccessTypes != null && !targetAccessTypes.contains(accessType)) { + continue; + } + Integer accessResult; if (isConditional) { @@ -386,16 +404,20 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu RangerPolicy policy = getPolicy(); - resourceACLs.setRoleAccessInfo(roleName, accessInfo.getKey(), accessResult, policy); + resourceACLs.setRoleAccessInfo(roleName, accessType, accessResult, policy); } } } - private void updateRowFiltersFromPolicy(boolean isConditional, RangerResourceACLs resourceACLs) { + private void updateRowFiltersFromPolicy(boolean isConditional, RangerResourceACLs resourceACLs, Set<String> targetAccessTypes) { PolicyACLSummary aclSummary = getPolicyACLSummary(); if (aclSummary != null) { for (RowFilterResult rowFilterResult : aclSummary.getRowFilters()) { + if (targetAccessTypes != null && !CollectionUtils.containsAny(targetAccessTypes, rowFilterResult.getAccessTypes())) { + continue; + } + rowFilterResult = copyRowFilter(rowFilterResult); if (isConditional) { @@ -407,11 +429,15 @@ public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvalu } } - private void updateDataMasksFromPolicy(boolean isConditional, RangerResourceACLs resourceACLs) { + private void updateDataMasksFromPolicy(boolean isConditional, RangerResourceACLs resourceACLs, Set<String> targetAccessTypes) { PolicyACLSummary aclSummary = getPolicyACLSummary(); if (aclSummary != null) { for (DataMaskResult dataMaskResult : aclSummary.getDataMasks()) { + if (targetAccessTypes != null && !CollectionUtils.containsAny(targetAccessTypes, dataMaskResult.getAccessTypes())) { + continue; + } + dataMaskResult = copyDataMask(dataMaskResult); if (isConditional) { 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 0a14b387a..2856ccc6b 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 @@ -104,7 +104,7 @@ public interface RangerPolicyEvaluator { void evaluate(RangerAccessRequest request, RangerAccessResult result); - void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, MatchType matchType, PolicyEngine policyEngine); + void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set<String> targetAccessTypes, MatchType matchType, PolicyEngine policyEngine); boolean isMatch(RangerAccessResource resource, Map<String, Object> evalContext); 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 71478f4bb..748efd681 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 @@ -51,6 +51,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.policyengine.gds.GdsPolicyEngine; import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil; import org.apache.ranger.plugin.util.*; @@ -698,6 +699,20 @@ public class RangerBasePlugin { } } + GdsPolicyEngine gdsPolicyEngine = getGdsPolicyEngine(); + + if (gdsPolicyEngine != null) { + RangerResourceACLs gdsACLs = gdsPolicyEngine.getResourceACLs(request); + + if (gdsACLs != null) { + if (ret != null) { + ret = getMergedResourceACLs(ret, gdsACLs); + } else { + ret = gdsACLs; + } + } + } + return ret; } @@ -1139,6 +1154,31 @@ public class RangerBasePlugin { return ret; } + public GdsPolicyEngine getGdsPolicyEngine() { + GdsPolicyEngine ret = null; + RangerAuthContext authContext = getCurrentRangerAuthContext(); + + if (authContext != null) { + Map<RangerContextEnricher, Object> contextEnricherMap = authContext.getRequestContextEnrichers(); + + if (MapUtils.isNotEmpty(contextEnricherMap)) { + Set<RangerContextEnricher> contextEnrichers = contextEnricherMap.keySet(); + + for (RangerContextEnricher enricher : contextEnrichers) { + if (enricher instanceof RangerGdsEnricher) { + RangerGdsEnricher gdsEnricher = (RangerGdsEnricher) enricher; + + ret = gdsEnricher.getGdsPolicyEngine(); + + break; + } + } + } + } + + return ret; + } + public static RangerResourceACLs getMergedResourceACLs(RangerResourceACLs baseACLs, RangerResourceACLs chainedACLs) { if (LOG.isDebugEnabled()) { LOG.debug("==> RangerBasePlugin.getMergedResourceACLs()"); @@ -1149,6 +1189,8 @@ public class RangerBasePlugin { overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.USER); overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.GROUP); overrideACLs(chainedACLs, baseACLs, RangerRolesUtil.ROLES_FOR.ROLE); + baseACLs.getDatasets().addAll(chainedACLs.getDatasets()); + baseACLs.getProjects().addAll(chainedACLs.getProjects()); if (LOG.isDebugEnabled()) { LOG.debug("<== RangerBasePlugin.getMergedResourceACLs() : ret:[" + baseACLs + "]"); diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/gds/TestGdsPolicyEngine.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/gds/TestGdsPolicyEngine.java index 83bfc99f5..b5ca483ad 100644 --- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/gds/TestGdsPolicyEngine.java +++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/gds/TestGdsPolicyEngine.java @@ -80,9 +80,17 @@ public class TestGdsPolicyEngine { RangerAccessRequestUtil.setResourceZoneNamesInContext(test.request, zoneNames); - GdsAccessResult result = policyEngine.evaluate(test.request); + if (test.result != null) { + GdsAccessResult result = policyEngine.evaluate(test.request); - assertEquals(test.name, test.result, result); + assertEquals(test.name, test.result, result); + } + + if (test.acls != null) { + RangerResourceACLs acls = policyEngine.getResourceACLs(test.request); + + assertEquals(test.name, test.acls, acls); + } } } @@ -97,6 +105,7 @@ public class TestGdsPolicyEngine { public String name; public RangerAccessRequest request; public GdsAccessResult result; + public RangerResourceACLs acls; } static class RangerAccessRequestDeserializer implements JsonDeserializer<RangerAccessRequest> { diff --git a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_engine_hive.json b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_engine_hive.json index 010baed5c..89fed5f9e 100644 --- a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_engine_hive.json +++ b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_engine_hive.json @@ -96,10 +96,10 @@ "id": 1, "name": "dataset-1", "policies": [ - { "id": 2001, "name": "dataset-3", "isEnabled": true, "isAuditEnabled": true, + { "id": 2001, "name": "dataset-1", "isEnabled": true, "isAuditEnabled": true, "resources": { "dataset-id": { "values": ["1"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} ] } ] @@ -111,7 +111,7 @@ { "id": 2002, "name": "dataset-2", "isEnabled": true, "isAuditEnabled": true, "resources": { "dataset-id": { "values": ["2"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} ] } ] @@ -123,7 +123,7 @@ { "id": 2003, "name": "dataset-3", "isEnabled": true, "isAuditEnabled": true, "resources": { "dataset-id": { "values": ["3"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} ] } ] @@ -135,7 +135,7 @@ { "id": 2004, "name": "dataset-4", "isEnabled": true, "isAuditEnabled": true, "resources": { "dataset-id": { "values": ["4"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "ds-user" ], "groups": []} ] } ] @@ -149,7 +149,7 @@ { "id": 3001, "name": "project-1", "isEnabled": true, "isAuditEnabled": true, "resources": { "project-id": { "values": ["1"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "proj-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "proj-user" ], "groups": []} ] } ] @@ -161,7 +161,7 @@ { "id": 3002, "name": "project-2", "isEnabled": true, "isAuditEnabled": true, "resources": { "project-id": { "values": ["2"] } }, "policyItems":[ - { "accesses":[ { "type": "_READ", "isAllowed": true } ], "users": [ "proj-user" ], "groups": []} + { "accesses":[ { "type": "_ALL", "isAllowed": true } ], "users": [ "proj-user" ], "groups": []} ] } ] @@ -376,6 +376,131 @@ "accessType": "update", "user": "ds-user", "userGroups": [] }, "result": { "datasets": null, "projects": null, "isAllowed": false, "isAudited": false, "policyId": -1 } + }, + + { + "name": "ACLs: database: sales", + "request": { "resource": { "elements": { "database": "sales" } } }, + "acls": { } + }, + { + "name": "ACLs: table: sales.prospects", + "request": { "resource": { "elements": { "database": "sales", "table": "prospects" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-1" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: table: sales.orders", + "request": { "resource": { "elements": { "database": "sales", "table": "orders" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-1" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: table: sales.non_existent_table", + "request": { "resource": { "elements": { "database": "sales", "table": "non_existent_table" } } }, + "acls": { } + }, + { + "name": "ACLs: column: sales.orders.created_time", + "request": { "resource": { "elements": { "database": "sales", "table": "orders", "column": "created_time" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-1" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: database: finance", + "request": { "resource": { "elements": { "database": "finance" } } }, + "acls": { } + }, + { + "name": "ACLs: table: finance.invoices", + "request": { "resource": { "elements": { "database": "finance", "table": "invoices" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-1", "dataset-2" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: table: finance.payments", + "request": { "resource": { "elements": { "database": "finance", "table": "payments" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-1", "dataset-2" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: database: shipping", + "request": { "resource": { "elements": { "database": "shipping" } } }, + "acls": { } + }, + { + "name": "ACLs: table: shipping.shipments", + "request": { "resource": { "elements": { "database": "shipping", "table": "shipments" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-2" ], + "projects": [ "project-1" ] + } + }, + { + "name": "ACLs: database: customers", + "request": { "resource": { "elements": { "database": "customers" } } }, + "acls": { } + }, + { + "name": "ACLs: table: customers.contact_info", + "request": { "resource": { "elements": { "database": "customers", "table": "contact_info" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } }, + "proj-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-3" ], + "projects": [ "project-2" ] + } + }, + { + "name": "ACLs: database: operations", + "request": { "resource": { "elements": { "database": "operations" } } }, + "acls": { } + }, + { + "name": "ACLs: table: operations.facilities", + "request": { "resource": { "elements": { "database": "operations", "table": "facilities" } } }, + "acls": { + "userACLs": { + "ds-user": { "select": { "result": 1, "isFinal": false } } + }, + "datasets": [ "dataset-4" ] + } } ] }