This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 5da81ab22 RANGER-5295: fix GDS policy evaluation handling of
row-filters (#646)
5da81ab22 is described below
commit 5da81ab22e0086a89334d613f322be6650bae210
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Thu Aug 28 12:50:16 2025 -0700
RANGER-5295: fix GDS policy evaluation handling of row-filters (#646)
---
.../policyengine/RangerPolicyEngineImpl.java | 33 +++++++++++++---
.../plugin/policyengine/gds/GdsPolicyEngine.java | 21 +++++++++-
.../policyengine/gds/gds_info_hive_row_filter.json | 5 +++
.../gds/test_gds_policy_hive_row_filter.json | 45 +++++++++++++++++++---
4 files changed, 92 insertions(+), 12 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 15628e458..3ae85edf8 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
@@ -1072,12 +1072,25 @@ private void updateFromGdsResult(RangerAccessResult
result) {
if (gdsResult != null) {
if (result.getPolicyType() == RangerPolicy.POLICY_TYPE_ACCESS) {
+ // pick access result from GDS policies only if there is no
decision yet
if (!result.getIsAccessDetermined() &&
gdsResult.getIsAllowed()) {
- result.setIsAllowed(true);
- result.setIsAccessDetermined(true);
- result.setPolicyId(gdsResult.getPolicyId());
- result.setPolicyVersion(gdsResult.getPolicyVersion());
-
result.setPolicyPriority(RangerPolicy.POLICY_PRIORITY_NORMAL);
+ copyFromGdsResult(gdsResult, result);
+ }
+ } else if (result.getPolicyType() ==
RangerPolicy.POLICY_TYPE_ROWFILTER) {
+ // pick row-filter from GDS policies only if there is no
decision yet
+ if (result.getPolicyId() == -1 &&
CollectionUtils.isNotEmpty(gdsResult.getRowFilters())) {
+ copyFromGdsResult(gdsResult, result);
+
+ result.setFilterExpr(gdsResult.getRowFilters().get(0));
+ }
+ } else if (result.getPolicyType() ==
RangerPolicy.POLICY_TYPE_DATAMASK) {
+ // pick data-mask from GDS policies only if there is no
decision yet
+ if (result.getPolicyId() == -1 &&
StringUtils.isNotEmpty(gdsResult.getMaskType())) {
+ copyFromGdsResult(gdsResult, result);
+
+ result.setMaskType(gdsResult.getMaskType());
+ result.setMaskedValue(gdsResult.getMaskedValue());
+ result.setMaskCondition(gdsResult.getMaskCondition());
}
}
@@ -1094,6 +1107,16 @@ private void updateFromGdsResult(RangerAccessResult
result) {
LOG.debug("<== updateFromGdsResult(result={})", result);
}
+ private void copyFromGdsResult(GdsAccessResult gdsResult,
RangerAccessResult result) {
+ if (gdsResult != null && result != null) {
+ result.setIsAllowed(true);
+ result.setIsAccessDetermined(true);
+ result.setPolicyId(gdsResult.getPolicyId());
+ result.setPolicyVersion(gdsResult.getPolicyVersion());
+ result.setPolicyPriority(RangerPolicy.POLICY_PRIORITY_NORMAL);
+ }
+ }
+
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/gds/GdsPolicyEngine.java
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/gds/GdsPolicyEngine.java
index 4bc1dc68b..2540eec96 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
@@ -62,6 +62,7 @@ public class GdsPolicyEngine {
public static final String RESOURCE_NAME_PROJECT_ID = "project-id";
private final ServiceGdsInfo gdsInfo;
+ private final RangerServiceDefHelper serviceDefHelper;
private final Set<String> allAccessTypes;
private final Map<Long, GdsProjectEvaluator> projects = new
HashMap<>();
private final Map<Long, GdsDatasetEvaluator> datasets = new
HashMap<>();
@@ -71,8 +72,9 @@ public class GdsPolicyEngine {
public GdsPolicyEngine(ServiceGdsInfo gdsInfo, RangerServiceDefHelper
serviceDefHelper, RangerPluginContext pluginContext) {
LOG.debug("==> RangerGdsPolicyEngine()");
- this.gdsInfo = gdsInfo;
- this.allAccessTypes = serviceDefHelper.getAllAccessTypes();
+ this.gdsInfo = gdsInfo;
+ this.serviceDefHelper = serviceDefHelper;
+ this.allAccessTypes = serviceDefHelper.getAllAccessTypes();
init(serviceDefHelper, pluginContext);
@@ -95,7 +97,22 @@ public GdsAccessResult evaluate(RangerAccessRequest request)
{
if (ret.getIsAllowed()) {
evaluate(request, RangerPolicy.POLICY_TYPE_DATAMASK, ret);
+ }
+
+ // consider the following:
+ // 1. accessed resource is table table1
+ // 2. a shared-resource allows the user access to only few
columns in table1
+ // In this case ret.getIsAllowed() will be false, since the user
doesn't have access
+ // to all columns of table1; still, row-filter specified in the
shared-resource must
+ // be included in the result.
+ if
(serviceDefHelper.isRowFilterSupported(request.getResource().getKeys())) {
+ boolean isAccessAllowed = ret.getIsAllowed();
+
evaluate(request, RangerPolicy.POLICY_TYPE_ROWFILTER, ret);
+
+ if (!isAccessAllowed) {
+ ret.setIsAllowed(false);
+ }
}
} else {
ret = null;
diff --git
a/agents-common/src/test/resources/policyengine/gds/gds_info_hive_row_filter.json
b/agents-common/src/test/resources/policyengine/gds/gds_info_hive_row_filter.json
index 76a2fe894..9b313fc7d 100644
---
a/agents-common/src/test/resources/policyengine/gds/gds_info_hive_row_filter.json
+++
b/agents-common/src/test/resources/policyengine/gds/gds_info_hive_row_filter.json
@@ -169,6 +169,11 @@
"id": 61, "dataShareId": 6, "conditionExpr": "", "accessTypes": [
"select" ],
"resource": { "database": { "values": [ "customers" ] }, "table": {
"values": [ "contact_info" ] } }, "rowFilter": { "filterExpr": "country = 'US'"
},
"subResourceType": "column", "subResource": { "values": [ "*" ] },
"subResourceMasks": null
+ },
+ {
+ "id": 71, "dataShareId": 6, "conditionExpr": "", "accessTypes": [
"select" ],
+ "resource": { "database": { "values": [ "customers" ] }, "table": {
"values": [ "shipping_address" ] } }, "rowFilter": { "filterExpr": "country =
'US'" },
+ "subResourceType": "column", "subResource": { "values": [ "phone",
"city", "zip" ] }, "subResourceMasks": [ { "values": [ "phone" ], "maskInfo": {
"dataMaskType": "MASK_SHOW_LAST_4" } }]
}
],
"gdsVersion": 1
diff --git
a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_row_filter.json
b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_row_filter.json
index 619eb3a14..4dbc256e6 100644
---
a/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_row_filter.json
+++
b/agents-common/src/test/resources/policyengine/gds/test_gds_policy_hive_row_filter.json
@@ -29,7 +29,7 @@
"resource": { "elements": { "database": "sales" } },
"accessType": "", "user": "ds-user", "userGroups": []
},
- "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ],
"allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true,
"policyId": 2001, "rowFilters": [ "created_time >= '2023-01-01' and
created_time < '2024-01-01'" ] }
+ "result": { "datasets": [ "dataset-1" ], "projects": [ "project-1" ],
"allowedByDatasets": [ "dataset-1" ], "isAllowed": true, "isAudited": true,
"policyId": 2001, "rowFilters": null }
},
{
"name": "table: finance.invoices, user: ds-user, access: select",
@@ -69,7 +69,7 @@
"resource": { "elements": { "database": "finance" } },
"accessType": "", "user": "ds-user", "userGroups": []
},
- "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [
"project-1" ], "allowedByDatasets": [ "dataset-1", "dataset-2" ], "isAllowed":
true, "isAudited": true, "policyId": 2001, "rowFilters": [ "created_time >=
'2023-01-01' and created_time < '2024-01-01'" ] }
+ "result": { "datasets": [ "dataset-1", "dataset-2" ], "projects": [
"project-1" ], "allowedByDatasets": [ "dataset-1", "dataset-2" ], "isAllowed":
true, "isAudited": true, "policyId": 2001, "rowFilters": null }
},
{
"name": "table: shipping.shipments, user: ds-user, access: select",
@@ -85,7 +85,7 @@
"resource": { "elements": { "database": "shipping" } },
"accessType": "", "user": "ds-user", "userGroups": []
},
- "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ],
"allowedByDatasets": [ "dataset-2" ], "isAllowed": true, "isAudited": true,
"policyId": 2002, "rowFilters": [ "created_time >= '2023-01-01' and
created_time < '2024-01-01'" ] }
+ "result": { "datasets": [ "dataset-2" ], "projects": [ "project-1" ],
"allowedByDatasets": [ "dataset-2" ], "isAllowed": true, "isAudited": true,
"policyId": 2002, "rowFilters": null }
},
{
"name": "table: customers.contact_info, user: ds-user, access:
select",
@@ -117,8 +117,43 @@
"resource": { "elements": { "database": "customers" } },
"accessType": "", "user": "ds-user", "userGroups": []
},
- "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [
"project-2", "project-4" ], "allowedByDatasets": [ "dataset-3", "dataset-6" ],
"isAllowed": true, "isAudited": true, "policyId": 2003, "rowFilters": [
"created_time >= '2023-01-01' and created_time < '2024-01-01'", "country =
'US'" ] }
+ "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [
"project-2", "project-4" ], "allowedByDatasets": [ "dataset-3", "dataset-6" ],
"isAllowed": true, "isAudited": true, "policyId": 2003, "rowFilters": null }
+ },
+
+ {
+ "name": "table: customers.shipping_address, user: ds-user, access:
select",
+ "request": {
+ "resource": { "elements": { "database": "customers", "table":
"shipping_address" } },
+ "accessType": "select", "user": "ds-user", "userGroups": []
+ },
+ "result": { "datasets": [ "dataset-6" ], "projects": [ "project-4" ],
"allowedByDatasets": [ "dataset-6" ], "isAllowed": false, "isAudited": true,
"policyId": 2006, "rowFilters": [ "country = 'US'" ] }
+ },
+ {
+ "name": "table: customers.shipping_address, user: ds3-user, access:
select",
+ "request": {
+ "resource": { "elements": { "database": "customers", "table":
"shipping_address" } },
+ "accessType": "select", "user": "ds3-user", "userGroups": []
+ },
+ "result": { "datasets": [ "dataset-6" ], "projects": [ "project-4" ],
"allowedByDatasets": null, "isAllowed": false, "isAudited": true, "policyId":
-1, "rowFilters": null }
},
+ {
+ "name": "table: customers.shipping_address, user: ds6-user, access:
select",
+ "request": {
+ "resource": { "elements": { "database": "customers", "table":
"shipping_address" } },
+ "accessType": "select", "user": "ds6-user", "userGroups": []
+ },
+ "result": { "datasets": [ "dataset-6" ], "projects": [ "project-4" ],
"allowedByDatasets": [ "dataset-6" ], "isAllowed": false, "isAudited": true,
"policyId": 2006, "rowFilters": [ "country = 'US'" ] }
+ },
+ {
+ "name": "database: customers, user: ds-user, access: _any",
+ "request": {
+ "resource": { "elements": { "database": "customers" } },
+ "accessType": "", "user": "ds-user", "userGroups": []
+ },
+ "result": { "datasets": [ "dataset-3", "dataset-6" ], "projects": [
"project-2", "project-4" ], "allowedByDatasets": [ "dataset-3", "dataset-6" ],
"isAllowed": true, "isAudited": true, "policyId": 2003, "rowFilters": null }
+ },
+
+
{
"name": "table: operations.facilities, user: ds-user, access: select",
"request": {
@@ -133,7 +168,7 @@
"resource": { "elements": { "database": "operations" } },
"accessType": "", "user": "ds-user", "userGroups": []
},
- "result": { "datasets": [ "dataset-4" ], "projects": null,
"allowedByDatasets": [ "dataset-4" ], "isAllowed": true, "isAudited": true,
"policyId": 2004, "rowFilters": [ "country = 'US'" ] }
+ "result": { "datasets": [ "dataset-4" ], "projects": null,
"allowedByDatasets": [ "dataset-4" ], "isAllowed": true, "isAudited": true,
"policyId": 2004, "rowFilters": null }
},