From e4b7f149f3abc0ab9615e8732dc78ccb83ef6bb5 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Wed, 6 Nov 2024 14:19:57 -0800 Subject: [PATCH] RANGER-4985: update GdsAccessResult to include fields allowedByDatasets and allowedByProjects --- .../policyengine/RangerAccessResult.java | 38 +++++-- .../policyengine/gds/GdsAccessResult.java | 98 ++++++++++++------- .../gds/GdsDataShareEvaluator.java | 12 +-- .../policyengine/gds/GdsDatasetEvaluator.java | 24 ++++- .../policyengine/gds/GdsPolicyEngine.java | 69 +++++++------ .../policyengine/gds/GdsProjectEvaluator.java | 15 ++- .../gds/test_gds_policy_engine_hive.json | 84 ++++++++++++---- 7 files changed, 241 insertions(+), 99 deletions(-) diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java index 402cbda681..4bf2617aa0 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerAccessResult.java @@ -29,12 +29,14 @@ import java.util.Set; public class RangerAccessResult { - public final static String KEY_MASK_TYPE = "maskType"; - public final static String KEY_MASK_CONDITION = "maskCondition"; - public final static String KEY_MASKED_VALUE = "maskedValue"; - private final static String KEY_FILTER_EXPR = "filterExpr"; - private final static String KEY_DATASETS = "datasets"; - private final static String KEY_PROJECTS = "projects"; + public final static String KEY_MASK_TYPE = "maskType"; + public final static String KEY_MASK_CONDITION = "maskCondition"; + public final static String KEY_MASKED_VALUE = "maskedValue"; + private final static String KEY_FILTER_EXPR = "filterExpr"; + private final static String KEY_DATASETS = "datasets"; + private final static String KEY_PROJECTS = "projects"; + private final static String KEY_ALLOWED_BY_DATASETS = "allowedByDatasets"; + private final static String KEY_ALLOWED_BY_PROJECTS = "allowedByProjects"; private final String serviceName; private final RangerServiceDef serviceDef; @@ -352,6 +354,30 @@ public void setProjects(Set projects) { } } + public Set getAllowedByDatasets() { + return additionalInfo == null ? null : (Set) additionalInfo.get(KEY_ALLOWED_BY_DATASETS); + } + + public void setAllowedByDatasets(Set datasets) { + if (datasets == null) { + removeAdditionalInfo(KEY_ALLOWED_BY_DATASETS); + } else { + addAdditionalInfo(KEY_ALLOWED_BY_DATASETS, datasets); + } + } + + public Set getAllowedByProjects() { + return additionalInfo == null ? null : (Set) additionalInfo.get(KEY_ALLOWED_BY_PROJECTS); + } + + public void setAllowedByProjects(Set projects) { + if (projects == null) { + removeAdditionalInfo(KEY_ALLOWED_BY_PROJECTS); + } else { + addAdditionalInfo(KEY_ALLOWED_BY_PROJECTS, projects); + } + } + @Override public String toString( ) { StringBuilder sb = new StringBuilder(); diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsAccessResult.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsAccessResult.java index b2158579fb..74a78e68d4 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsAccessResult.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsAccessResult.java @@ -22,41 +22,19 @@ import java.util.*; public class GdsAccessResult { - private Set datasets; - private Set projects; private boolean isAllowed; private boolean isAudited; private long policyId = -1; private Long policyVersion; + private Set datasets; + private Set projects; + private Set allowedByDatasets; + private Set allowedByProjects; public GdsAccessResult() { } - public void addDataset(String name) { - if (datasets == null) { - datasets = new HashSet<>(); - } - - datasets.add(name); - } - - public Set getDatasets() { - return datasets; - } - - public void addProject(String name) { - if (projects == null) { - projects = new HashSet<>(); - } - - projects.add(name); - } - - public Set getProjects() { - return projects; - } - public boolean getIsAllowed() { return isAllowed; } @@ -89,9 +67,57 @@ public void setPolicyVersion(Long policyVersion) { this.policyVersion = policyVersion; } + public Set getDatasets() { + return datasets; + } + + public Set getProjects() { + return projects; + } + + public Set getAllowedByDatasets() { + return allowedByDatasets; + } + + public Set getAllowedByProjects() { + return allowedByProjects; + } + + public void addDataset(String name) { + if (datasets == null) { + datasets = new HashSet<>(); + } + + datasets.add(name); + } + + public void addProject(String name) { + if (projects == null) { + projects = new HashSet<>(); + } + + projects.add(name); + } + + public void addAllowedByDataset(String name) { + if (allowedByDatasets == null) { + allowedByDatasets = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + } + + allowedByDatasets.add(name); + } + + public void addAllowedByProject(String name) { + if (allowedByProjects == null) { + allowedByProjects = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + } + + allowedByProjects.add(name); + } + @Override public int hashCode() { - return Objects.hash(datasets, projects, isAllowed, isAudited, policyId, policyVersion); + return Objects.hash(isAllowed, isAudited, policyId, policyVersion, datasets, projects, allowedByDatasets, allowedByProjects); } @Override @@ -103,12 +129,14 @@ public boolean equals(Object obj) { } else { GdsAccessResult other = (GdsAccessResult) obj; - return Objects.equals(datasets, other.datasets) && - Objects.equals(projects, other.projects) && - Objects.equals(isAllowed, other.isAllowed) && + return Objects.equals(isAllowed, other.isAllowed) && Objects.equals(isAudited, other.isAudited) && Objects.equals(policyId, other.policyId) && - Objects.equals(policyVersion, other.policyVersion); + Objects.equals(policyVersion, other.policyVersion) && + Objects.equals(datasets, other.datasets) && + Objects.equals(projects, other.projects) && + Objects.equals(allowedByDatasets, other.allowedByDatasets) && + Objects.equals(allowedByProjects, other.allowedByProjects); } } @@ -123,12 +151,14 @@ public String toString( ) { public StringBuilder toString(StringBuilder sb) { sb.append("RangerGdsAccessResult={"); - sb.append("datasets={").append(datasets).append("}"); - sb.append(", projects={").append(projects).append("}"); - sb.append(", isAllowed={").append(isAllowed).append("}"); + sb.append("isAllowed={").append(isAllowed).append("}"); sb.append(", isAudited={").append(isAudited).append("}"); sb.append(", policyId={").append(policyId).append("}"); sb.append(", policyVersion={").append(policyVersion).append("}"); + sb.append(", datasets={").append(datasets).append("}"); + sb.append(", projects={").append(projects).append("}"); + sb.append(", allowedByDatasets={").append(allowedByDatasets).append("}"); + sb.append(", allowedByProjects={").append(allowedByProjects).append("}"); sb.append("}"); return sb; 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 98f8da493b..39cd154247 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 @@ -30,10 +30,10 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; @@ -75,7 +75,7 @@ public String getZoneName() { public Set getDefaultAccessTypes() { return dsh.getDefaultAccessTypes(); } - public Collection getResourceEvaluators() { return evaluators; } + public Set getResourceEvaluators() { return evaluators; } public List getDshidEvaluators() { return dshidEvaluators; } @@ -100,16 +100,16 @@ public boolean isInProject(Long projectId) { return dshidEvaluators.stream().anyMatch(e -> e.getDatasetEvaluator().isInProject(projectId) && e.isActive()); } - public void collectDatasets(RangerAccessRequest request, GdsAccessResult result, Set datasetIds) { - LOG.debug("==> GdsDataShareEvaluator.collectDatasets({}, {})", request, result); + public void collectDatasets(RangerAccessRequest request, Map> datasetsToEval) { + LOG.debug("==> GdsDataShareEvaluator.collectDatasets({}, {})", request, datasetsToEval); boolean isAllowed = conditionEvaluator == null || conditionEvaluator.isMatched(request); if (isAllowed) { - dshidEvaluators.stream().filter(e -> !datasetIds.contains(e.getDatasetId()) && e.isAllowed(request) && e.getDatasetEvaluator().isActive()).map(GdsDshidEvaluator::getDatasetId).forEach(datasetIds::add); + dshidEvaluators.stream().filter(dshid -> dshid.isAllowed(request) && dshid.getDatasetEvaluator().isActive()).forEach(dshid -> datasetsToEval.computeIfAbsent(dshid.getDatasetEvaluator(), s -> new TreeSet<>(GdsDataShareEvaluator.EVAL_ORDER_COMPARATOR)).add(this)); } - LOG.debug("<== GdsDataShareEvaluator.collectDatasets({}, {})", request, result); + LOG.debug("<== GdsDataShareEvaluator.collectDatasets({}, {})", request, datasetsToEval); } public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls) { 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 9c37b67835..7298825c21 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 @@ -27,11 +27,13 @@ import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; import org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.ServiceGdsInfo.DatasetInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -97,8 +99,8 @@ public boolean isActive() { return scheduleEvaluator == null || scheduleEvaluator.isApplicable(System.currentTimeMillis()); } - public void evaluate(RangerAccessRequest request, GdsAccessResult result, Set projectIds) { - LOG.debug("==> GdsDatasetEvaluator.evaluate({}, {})", request, result); + public void evaluate(RangerAccessRequest request, GdsAccessResult result, Collection projectsToEval) { + LOG.debug("==> GdsDatasetEvaluator.evaluate({}, {}, {})", request, result, projectsToEval); if (isActive()) { result.addDataset(getName()); @@ -107,7 +109,19 @@ public void evaluate(RangerAccessRequest request, GdsAccessResult result, Set e.evaluate(datasetRequest, datasetResult)); + try { + RangerAccessRequestUtil.setAccessTypeResults(datasetRequest.getContext(), null); + RangerAccessRequestUtil.setAccessTypeACLResults(datasetRequest.getContext(), null); + + policyEvaluators.forEach(e -> e.evaluate(datasetRequest, datasetResult)); + } finally { + RangerAccessRequestUtil.setAccessTypeResults(datasetRequest.getContext(), null); + RangerAccessRequestUtil.setAccessTypeACLResults(datasetRequest.getContext(), null); + } + + if (datasetResult.getIsAllowed()) { + result.addAllowedByDataset(getName()); + } if (!result.getIsAllowed()) { if (datasetResult.getIsAllowed()) { @@ -122,10 +136,10 @@ public void evaluate(RangerAccessRequest request, GdsAccessResult result, Set !projectIds.contains(e.getProjectId()) && e.isAllowed(request) && e.getProjectEvaluator().isActive()).map(GdsDipEvaluator::getProjectId).forEach(projectIds::add); + dipEvaluators.stream().filter(e -> e.isAllowed(request) && e.getProjectEvaluator().isActive()).forEach(dip -> projectsToEval.add(dip.getProjectEvaluator())); } - LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {})", request, result); + LOG.debug("<== GdsDatasetEvaluator.evaluate({}, {}, {})", request, result, projectsToEval); } public void getResourceACLs(RangerAccessRequest request, RangerResourceACLs acls, boolean isConditional, Set allowedAccessTypes) { 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 972e8bf28b..ddac8da1a9 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 @@ -47,6 +47,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeMap; import java.util.TreeSet; import java.util.stream.Collectors; @@ -92,23 +93,23 @@ public GdsAccessResult evaluate(RangerAccessRequest request) { RangerAccessRequestUtil.setIsAnyAccessInContext(request.getContext(), Boolean.TRUE); } - Collection dataShares = getDataShareEvaluators(request); + Map> dshResources = getDataShareResources(request); - if (!dataShares.isEmpty()) { - ret = new GdsAccessResult(); + if (!dshResources.isEmpty()) { + Map> datasetsToEval = new TreeMap<>(GdsDatasetEvaluator.EVAL_ORDER_COMPARATOR); - Set datasetIds = new HashSet<>(); + dshResources.keySet().forEach(e -> e.collectDatasets(request, datasetsToEval)); - dataShares.forEach(e -> e.collectDatasets(request, ret, datasetIds)); + if (!datasetsToEval.isEmpty()) { + ret = new GdsAccessResult(); - if (!datasetIds.isEmpty()) { - Set projectIds = new HashSet<>(); + Set projectsToEval = new TreeSet<>(GdsProjectEvaluator.EVAL_ORDER_COMPARATOR); - evaluateDatasetPolicies(datasetIds, request, ret, projectIds); + evaluateDatasetPolicies(datasetsToEval.keySet(), request, ret, projectsToEval); - if (!projectIds.isEmpty()) { - evaluateProjectPolicies(projectIds, request, ret); - } + evaluateProjectPolicies(projectsToEval, request, ret); + } else { + ret = null; } } else { ret = null; @@ -128,7 +129,7 @@ public GdsAccessResult evaluate(RangerAccessRequest request) { public RangerResourceACLs getResourceACLs(RangerAccessRequest request) { RangerResourceACLs ret = new RangerResourceACLs(); - getDataShareEvaluators(request).forEach(e -> e.getResourceACLs(request, ret)); + getDataShareResources(request).keySet().forEach(e -> e.getResourceACLs(request, ret)); ret.finalizeAcls(); @@ -336,10 +337,10 @@ private void preprocess(RangerServiceDefHelper serviceDefHelper) { gdsServiceDef.getAccessTypes().addAll(serviceDefHelper.getServiceDef().getAccessTypes()); } - private Collection getDataShareEvaluators(RangerAccessRequest request) { - LOG.debug("==> RangerGdsPolicyEngine.getDataShareEvaluators({})", request); + private Map> getDataShareResources(RangerAccessRequest request) { + LOG.debug("==> RangerGdsPolicyEngine.getDataShareResources({})", request); - final Collection ret; + final Map> ret; if (!dataShares.isEmpty()) { Set zoneNames = RangerAccessRequestUtil.getResourceZoneNamesFromContext(request.getContext()); @@ -347,29 +348,29 @@ private Collection getDataShareEvaluators(RangerAccessReq if (zoneNames == null || zoneNames.isEmpty()) { zoneNames = Collections.singleton(StringUtils.EMPTY); // unzoned } else if (zoneNames.size() > 1 && !request.isAccessTypeAny()) { - LOG.warn("RangerGdsPolicyEngine.getDataShareEvaluators(): resource matches multiple zones and accessType is not ANY - ignored. resource={}, zones={}", request.getResource(), zoneNames); + LOG.warn("RangerGdsPolicyEngine.getDataShareResources(): resource matches multiple zones and accessType is not ANY - ignored. resource={}, zones={}", request.getResource(), zoneNames); zoneNames = Collections.emptySet(); } - ret = new TreeSet<>(GdsDataShareEvaluator.EVAL_ORDER_COMPARATOR); + ret = new TreeMap<>(GdsDataShareEvaluator.EVAL_ORDER_COMPARATOR); - zoneNames.stream().map(zoneResources::get).filter(Objects::nonNull).forEach(zr -> zr.collectMatchingDataShares(request, ret)); + zoneNames.stream().map(zoneResources::get).filter(Objects::nonNull).forEach(zr -> zr.collectDataShareResources(request, ret)); } else { - ret = Collections.emptyList(); + ret = Collections.emptyMap(); } - LOG.debug("<== RangerGdsPolicyEngine.getDataShareEvaluators({}): {}", request, ret); + LOG.debug("<== RangerGdsPolicyEngine.getDataShareResources({}): {}", request, ret); return ret; } - private void evaluateDatasetPolicies(Set datasetIds, RangerAccessRequest request, GdsAccessResult result, Set projectIds) { - datasetIds.stream().map(datasets::get).filter(Objects::nonNull).sorted(GdsDatasetEvaluator.EVAL_ORDER_COMPARATOR).forEach(e -> e.evaluate(request, result, projectIds)); + private void evaluateDatasetPolicies(Set datasets, RangerAccessRequest request, GdsAccessResult result, Set projectsToEval) { + datasets.forEach(e -> e.evaluate(request, result, projectsToEval)); } - private void evaluateProjectPolicies(Set projectIds, RangerAccessRequest request, GdsAccessResult result) { - projectIds.stream().map(projects::get).filter(Objects::nonNull).sorted(GdsProjectEvaluator.EVAL_ORDER_COMPARATOR).forEach(e -> e.evaluate(request, result)); + private void evaluateProjectPolicies(Set projects, RangerAccessRequest request, GdsAccessResult result) { + projects.forEach(e -> e.evaluate(request, result)); } private GdsDatasetEvaluator getDatasetEvaluator(String dsName) { @@ -417,11 +418,23 @@ public GdsZoneResources(String zoneName, List evalua public String getZoneName() { return zoneName; } - public void collectMatchingDataShares(RangerAccessRequest request, Collection dshEvaluators) { - Collection evaluators = RangerResourceEvaluatorsRetriever.getEvaluators(resourceTries, request.getResource().getAsMap(), request.getResourceElementMatchingScopes()); + public void collectDataShareResources(RangerAccessRequest request, Map> dshResources) { + Collection resources = RangerResourceEvaluatorsRetriever.getEvaluators(resourceTries, request.getResource().getAsMap(), request.getResourceElementMatchingScopes()); + + if (resources != null) { + for (GdsSharedResourceEvaluator resource : resources) { + if (!resource.isAllowed(request)) { + continue; + } + + GdsDataShareEvaluator dataShare = dataShares.get(resource.getDataShareId()); + + if (dataShare == null) { + continue; + } - if (evaluators != null) { - evaluators.stream().filter(e -> e.isAllowed(request)).map(GdsSharedResourceEvaluator::getDataShareId).distinct().map(dataShares::get).filter(Objects::nonNull).forEach(dshEvaluators::add); + dshResources.computeIfAbsent(dataShare, l -> new TreeSet<>(GdsSharedResourceEvaluator.EVAL_ORDER_COMPARATOR)).add(resource); + } } } 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 89324ddb40..ea47702395 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 @@ -27,6 +27,7 @@ import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; import org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator; import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.apache.ranger.plugin.util.ServiceGdsInfo.ProjectInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -100,8 +101,18 @@ public void evaluate(RangerAccessRequest request, GdsAccessResult result) { GdsProjectAccessRequest projectRequest = new GdsProjectAccessRequest(getId(), gdsServiceDef, request); RangerAccessResult projectResult = projectRequest.createAccessResult(); - for (RangerPolicyEvaluator policyEvaluator : policyEvaluators) { - policyEvaluator.evaluate(projectRequest, projectResult); + try { + RangerAccessRequestUtil.setAllRequestedAccessTypes(projectRequest.getContext(), null); + RangerAccessRequestUtil.setAccessTypeACLResults(projectRequest.getContext(), null); + + policyEvaluators.forEach(e -> e.evaluate(projectRequest, projectResult)); + } finally { + RangerAccessRequestUtil.setAccessTypeResults(projectRequest.getContext(), null); + RangerAccessRequestUtil.setAccessTypeACLResults(projectRequest.getContext(), null); + } + + if (projectResult.getIsAllowed()) { + result.addAllowedByProject(getName()); } if (!result.getIsAllowed()) { 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 a5e3636b39..969c184f7e 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 @@ -40,7 +40,7 @@ "resource": { "elements": { "database": "sales", "table": "prospects" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } }, { "name": "table: sales.orders, user: ds-user, access: select", @@ -48,7 +48,7 @@ "resource": { "elements": { "database": "sales", "table": "orders" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } }, { "name": "database: sales, user: ds-user, access: _any", @@ -56,7 +56,7 @@ "resource": { "elements": { "database": "sales" } }, "accessType": "", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } }, { "name": "table: finance.invoices, user: ds-user, access: select", @@ -64,7 +64,23 @@ "resource": { "elements": { "database": "finance", "table": "invoices" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1", "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + }, + { + "name": "table: finance.invoices, user: ds1-user, access: select", + "request": { + "resource": { "elements": { "database": "finance", "table": "invoices" } }, + "accessType": "select", "user": "ds1-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + }, + { + "name": "table: finance.invoices, user: ds2-user, access: select", + "request": { + "resource": { "elements": { "database": "finance", "table": "invoices" } }, + "accessType": "select", "user": "ds2-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2002 } }, { "name": "table: finance.payments, user: ds-user, access: select", @@ -72,7 +88,7 @@ "resource": { "elements": { "database": "finance", "table": "payments" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1", "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } }, { "name": "database: finance, user: ds-user, access: _any", @@ -80,7 +96,7 @@ "resource": { "elements": { "database": "finance" } }, "accessType": "", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-1", "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2001 } }, { "name": "table: shipping.shipments, user: ds-user, access: select", @@ -88,7 +104,7 @@ "resource": { "elements": { "database": "shipping", "table": "shipments" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2002 } + "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2002 } }, { "name": "database: shipping, user: ds-user, access: _any", @@ -96,7 +112,7 @@ "resource": { "elements": { "database": "shipping" } }, "accessType": "", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 2002 } + "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "allowedByDatasets": [ "dataset-2" ], "isAllowed": true, "isAudited": true, "policyId": 2002 } }, { "name": "table: customers.contact_info, user: ds-user, access: select", @@ -104,7 +120,23 @@ "resource": { "elements": { "database": "customers", "table": "contact_info" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "isAllowed": true, "isAudited": true, "policyId": 2003 } + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByDatasets": [ "dataset-3", "dataset-6" ], "isAllowed": true, "isAudited": true, "policyId": 2003 } + }, + { + "name": "table: customers.contact_info, user: ds3-user, access: select", + "request": { + "resource": { "elements": { "database": "customers", "table": "contact_info" } }, + "accessType": "select", "user": "ds3-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByDatasets": [ "dataset-3" ], "isAllowed": true, "isAudited": true, "policyId": 2003 } + }, + { + "name": "table: customers.contact_info, user: ds6-user, access: select", + "request": { + "resource": { "elements": { "database": "customers", "table": "contact_info" } }, + "accessType": "select", "user": "ds6-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByDatasets": [ "dataset-6" ], "isAllowed": true, "isAudited": true, "policyId": 2006 } }, { "name": "database: customers, user: ds-user, access: _any", @@ -112,7 +144,7 @@ "resource": { "elements": { "database": "customers" } }, "accessType": "", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "isAllowed": true, "isAudited": true, "policyId": 2003 } + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByDatasets": [ "dataset-3", "dataset-6" ], "isAllowed": true, "isAudited": true, "policyId": 2003 } }, { "name": "table: operations.facilities, user: ds-user, access: select", @@ -120,7 +152,7 @@ "resource": { "elements": { "database": "operations", "table": "facilities" } }, "accessType": "select", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-4" ], "projects": null, "isAllowed": true, "isAudited": true, "policyId": 2004 } + "result": { "datasets": [ "dataset-4" ], "projects": null, "allowedByDatasets": [ "dataset-4" ], "isAllowed": true, "isAudited": true, "policyId": 2004 } }, { "name": "database: operations, user: ds-user, access: _any", @@ -128,7 +160,7 @@ "resource": { "elements": { "database": "operations" } }, "accessType": "", "user": "ds-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-4" ], "projects": null, "isAllowed": true, "isAudited": true, "policyId": 2004 } + "result": { "datasets": [ "dataset-4" ], "projects": null, "allowedByDatasets": [ "dataset-4" ], "isAllowed": true, "isAudited": true, "policyId": 2004 } }, @@ -138,7 +170,7 @@ "resource": { "elements": { "database": "sales", "table": "prospects" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } + "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "allowedByProjects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } }, { "name": "table: sales.orders, user: proj-user, access: select", @@ -146,7 +178,7 @@ "resource": { "elements": { "database": "sales", "table": "orders" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } + "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ], "allowedByProjects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } }, { "name": "table: finance.invoices, user: proj-user, access: select", @@ -154,7 +186,7 @@ "resource": { "elements": { "database": "finance", "table": "invoices" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByProjects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } }, { "name": "table: finance.payments, user: proj-user, access: select", @@ -162,7 +194,7 @@ "resource": { "elements": { "database": "finance", "table": "payments" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } + "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [ "project-1" ], "allowedByProjects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } }, { "name": "table: shipping.shipments, user: proj-user, access: select", @@ -170,7 +202,7 @@ "resource": { "elements": { "database": "shipping", "table": "shipments" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } + "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ], "allowedByProjects": [ "project-1" ], "isAllowed": true, "isAudited": true, "policyId": 3001 } }, { "name": "table: customers.contact_info, user: proj-user, access: select", @@ -178,7 +210,23 @@ "resource": { "elements": { "database": "customers", "table": "contact_info" } }, "accessType": "select", "user": "proj-user", "userGroups": [] }, - "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "isAllowed": true, "isAudited": true, "policyId": 3002 } + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByProjects": [ "project-2", "project-4" ], "isAllowed": true, "isAudited": true, "policyId": 3002 } + }, + { + "name": "table: customers.contact_info, user: proj2-user, access: select", + "request": { + "resource": { "elements": { "database": "customers", "table": "contact_info" } }, + "accessType": "select", "user": "proj2-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByProjects": [ "project-2" ], "isAllowed": true, "isAudited": true, "policyId": 3002 } + }, + { + "name": "table: customers.contact_info, user: proj4-user, access: select", + "request": { + "resource": { "elements": { "database": "customers", "table": "contact_info" } }, + "accessType": "select", "user": "proj4-user", "userGroups": [] + }, + "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [ "project-2", "project-4" ], "allowedByProjects": [ "project-4" ], "isAllowed": true, "isAudited": true, "policyId": 3004 } }, { "name": "table: operations.facilities, user: proj-user, access: select",