You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2022/08/24 17:11:00 UTC

[ranger] branch ranger-2.4 updated: RANGER-3865: support user attribute references in masking expressions

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

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


The following commit(s) were added to refs/heads/ranger-2.4 by this push:
     new a19f7a336 RANGER-3865: support user attribute references in masking expressions
a19f7a336 is described below

commit a19f7a3367e19be543e5188f4d0a3a96703b03c3
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Wed Aug 24 03:45:48 2022 -0700

    RANGER-3865: support user attribute references in masking expressions
    
    (cherry picked from commit 4ea5a785f6f57a4b865374ddfe75dc914eba0323)
---
 .../RangerDefaultDataMaskPolicyItemEvaluator.java  |  37 ++++++-
 .../plugin/policyengine/TestPolicyEngine.java      |  25 +++--
 ...gine_hive_mask_filter_with_req_expressions.json | 109 +++++++++++++++++++++
 3 files changed, 159 insertions(+), 12 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultDataMaskPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultDataMaskPolicyItemEvaluator.java
index 8d9969a3f..d979e97e1 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultDataMaskPolicyItemEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultDataMaskPolicyItemEvaluator.java
@@ -18,6 +18,7 @@
  */
 package org.apache.ranger.plugin.policyevaluator;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerDataMaskPolicyItem;
@@ -25,15 +26,34 @@ import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo;
 import org.apache.ranger.plugin.policyengine.RangerAccessResult;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.apache.ranger.plugin.util.RangerRequestExprResolver;
 
 
 public class RangerDefaultDataMaskPolicyItemEvaluator extends RangerDefaultPolicyItemEvaluator implements RangerDataMaskPolicyItemEvaluator {
-	final private RangerDataMaskPolicyItem dataMaskPolicyItem;
+	final private RangerDataMaskPolicyItem  dataMaskPolicyItem;
+	final private RangerRequestExprResolver maskedValueExprResolver;
+	final private RangerRequestExprResolver maskConditionExprResolver;
 
 	public RangerDefaultDataMaskPolicyItemEvaluator(RangerServiceDef serviceDef, RangerPolicy policy, RangerDataMaskPolicyItem policyItem, int policyItemIndex, RangerPolicyEngineOptions options) {
 		super(serviceDef, policy, policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DATAMASK, policyItemIndex, options);
 
 		dataMaskPolicyItem = policyItem;
+
+		RangerPolicyItemDataMaskInfo dataMaskInfo  = dataMaskPolicyItem != null ? dataMaskPolicyItem.getDataMaskInfo() : null;
+		String                       maskedValue   = dataMaskInfo != null ? dataMaskInfo.getValueExpr() : null;
+		String                       maskCondition = dataMaskInfo != null ? dataMaskInfo.getConditionExpr() : null;
+
+		if (StringUtils.isNotBlank(maskedValue) && RangerRequestExprResolver.hasExpressions(maskedValue)) {
+			maskedValueExprResolver = new RangerRequestExprResolver(maskedValue, getServiceType());
+		} else {
+			maskedValueExprResolver = null;
+		}
+
+		if (StringUtils.isNotBlank(maskCondition) && RangerRequestExprResolver.hasExpressions(maskCondition)) {
+			maskConditionExprResolver = new RangerRequestExprResolver(maskCondition, getServiceType());
+		} else {
+			maskConditionExprResolver = null;
+		}
 	}
 
 	@Override
@@ -47,8 +67,19 @@ public class RangerDefaultDataMaskPolicyItemEvaluator extends RangerDefaultPolic
 
 		if (dataMaskInfo != null) {
 			result.setMaskType(dataMaskInfo.getDataMaskType());
-			result.setMaskCondition(dataMaskInfo.getConditionExpr());
-			result.setMaskedValue(dataMaskInfo.getValueExpr());
+
+			if (maskedValueExprResolver != null) {
+				result.setMaskedValue(maskedValueExprResolver.resolveExpressions(result.getAccessRequest()));
+			} else {
+				result.setMaskedValue(dataMaskInfo.getValueExpr());
+			}
+
+			if (maskConditionExprResolver != null) {
+				result.setMaskCondition(maskConditionExprResolver.resolveExpressions(result.getAccessRequest()));
+			} else {
+				result.setMaskCondition(dataMaskInfo.getConditionExpr());
+			}
+
 			result.setIsAccessDetermined(true);
 			result.setPolicyPriority(policyEvaluator.getPolicyPriority());
 			result.setPolicyId(policyEvaluator.getPolicyId());
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
index e6bd2f4f8..59c50e4ca 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
@@ -349,6 +349,13 @@ public class TestPolicyEngine {
 		runTestsFromResourceFiles(resourceFiles);
 	}
 
+	@Test
+	public void testPolicyEngine_hiveMaskingWithReqExpressions() {
+		String[] resourceFiles = {"/policyengine/test_policyengine_hive_mask_filter_with_req_expressions.json"};
+
+		runTestsFromResourceFiles(resourceFiles);
+	}
+
 	@Test
 	public void testPolicyEngine_hiveTagMasking() {
 		String[] resourceFiles = {"/policyengine/test_policyengine_tag_hive_mask.json"};
@@ -680,18 +687,18 @@ public class TestPolicyEngine {
 
 			RangerAccessResultProcessor auditHandler = new RangerDefaultAuditHandler();
 
-			if(test.result != null) {
-                RangerAccessResult expected = test.result;
-                RangerAccessResult result;
+			if (MapUtils.isNotEmpty(test.userAttributes) || MapUtils.isNotEmpty(test.groupAttributes)) {
+				RangerUserStore userStore = new RangerUserStore();
 
-                if (MapUtils.isNotEmpty(test.userAttributes) || MapUtils.isNotEmpty(test.groupAttributes)) {
-                    RangerUserStore userStore = new RangerUserStore();
+				userStore.setUserAttrMapping(test.userAttributes);
+				userStore.setGroupAttrMapping(test.groupAttributes);
 
-                    userStore.setUserAttrMapping(test.userAttributes);
-                    userStore.setGroupAttrMapping(test.groupAttributes);
+				RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
+			}
 
-                    RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
-                }
+			if(test.result != null) {
+                RangerAccessResult expected = test.result;
+                RangerAccessResult result;
 
 				result   = policyEngine.evaluatePolicies(request, RangerPolicy.POLICY_TYPE_ACCESS, auditHandler);
 
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_hive_mask_filter_with_req_expressions.json b/agents-common/src/test/resources/policyengine/test_policyengine_hive_mask_filter_with_req_expressions.json
new file mode 100644
index 000000000..5a4637008
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_hive_mask_filter_with_req_expressions.json
@@ -0,0 +1,109 @@
+{
+  "serviceName": "hivedev",
+
+  "serviceDef": {
+    "name": "hive", "id": 3,
+    "resources": [
+      { "name": "database", "level": 1,                       "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Hive Database", "description": "Hive Database" },
+      { "name": "table",    "level": 2, "parent": "database", "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Hive Table",    "description": "Hive Table" },
+      { "name": "udf",      "level": 2, "parent": "database", "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Hive UDF",      "description": "Hive UDF" },
+      { "name": "column",   "level": 3, "parent": "table",    "mandatory": true, "lookupSupported": true, "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Hive Column",   "description": "Hive Column" }
+    ],
+    "accessTypes": [
+      { "name": "select", "label": "Select" },
+      { "name": "update", "label": "Update" },
+      { "name": "create", "label": "Create" },
+      { "name": "drop",   "label": "Drop" },
+      { "name": "alter",  "label": "Alter" },
+      { "name": "index",  "label": "Index" },
+      { "name": "lock",   "label": "Lock" },
+      { "name": "all",    "label": "All", "impliedGrants": [ "select", "update", "create", "drop", "alter", "index", "lock" ] }
+    ],
+    "dataMaskDef": {
+      "maskTypes": [
+        { "itemId": 1,  "name": "MASK",    "label": "Mask",    "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'" },
+        { "itemId": 2,  "name": "SHUFFLE", "label": "Shuffle", "description": "Randomly shuffle the contents" },
+        { "itemId": 10, "name": "NULL",   "label": "NULL",    "description": "Replace with NULL" },
+        { "itemId": 11, "name": "CUSTOM", "label": "CUSTOM",  "description": "Custom expression" }
+      ],
+      "accessTypes": [
+        { "name": "select", "label": "Select" }
+      ],
+      "resources": [
+        { "name": "database", "matcherOptions": { "wildCard":false } },
+        { "name": "table",    "matcherOptions": { "wildCard":false } },
+        { "name": "column",   "matcherOptions": { "wildCard":false } }
+      ]
+    },
+    "rowFilterDef": {
+      "accessTypes": [
+        { "name": "select", "label": "Select" }
+      ],
+      "resources": [
+        { "name": "database", "matcherOptions": { "wildCard":false } },
+        { "name": "table",    "matcherOptions": { "wildCard":false } }
+      ]
+    }
+  },
+
+  "policies": [
+    { "id": 1, "name": "db=*: audit-all-access", "isEnabled": true, "isAuditEnabled": true,
+      "resources": { "database": { "values": [ "*" ] }, "table": { "values": [ "*" ] }, "column": { "values": [ "*" ] } },
+      "policyItems": [
+        { "accesses": [ { "type": "all", "isAllowed": true } ], "users": [ "hive", "user1", "user2" ], "groups": [ "public" ], "delegateAdmin":false }
+      ]
+    },
+    { "id": 101, "name": "db=employee, table=personal, column=ssn: mask ssn column", "isEnabled": true, "isAuditEnabled": true, "policyType": 1,
+      "resources": { "database": { "values": [ "employee" ] }, "table": { "values": [ "personal" ] }, "column": { "values": [ "ssn" ] } },
+      "dataMaskPolicyItems": [
+        { "accesses": [ { "type": "select", "isAllowed": true } ], "groups": [ "public" ], "delegateAdmin":false,
+          "dataMaskInfo": { "dataMaskType": "CUSTOM", "valueExpr": "CASE WHEN dept = '${{USER.dept}}' THEN {col} ELSE mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1') END" }
+        }
+      ]
+    },
+    { "id": 201, "name": "db=employee, table=personal", "isEnabled": true, "isAuditEnabled": true, "policyType": 2,
+      "resources": { "database": { "values": [ "employee" ] }, "table": { "values": [ "personal" ] } },
+      "rowFilterPolicyItems": [
+        { "accesses": [ { "type": "select", "isAllowed": true } ], "groups": [ "public" ], "delegateAdmin":false,
+          "rowFilterInfo": { "filterExpr": "dept='${{USER.dept}}'" }
+        }
+      ]
+    }
+  ],
+
+  "tests": [
+    { "name": "'select ssn from employee.personal;' for user1 - maskType=CUSTOM",
+      "request": {
+        "resource": { "elements": { "database": "employee", "table": "personal", "column": "ssn" } },
+        "accessType": "select", "user": "user1", "userGroups": [], "requestData": "select ssn from employee.personal;' for user1"
+      },
+      "userAttributes": { "user1": { "dept": "engg" }, "user2": { "dept": "r&d" } },
+      "dataMaskResult": { "additionalInfo": { "maskType": "CUSTOM", "maskCondition":null, "maskedValue": "CASE WHEN dept = 'engg' THEN {col} ELSE mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1') END"}, "policyId": 101}
+    },
+    { "name": "'select ssn from employee.personal;' for user2 - maskType=CUSTOM",
+      "request": {
+        "resource": { "elements": { "database": "employee", "table": "personal", "column": "ssn" } },
+        "accessType": "select", "user": "user2", "userGroups": [], "requestData": "select ssn from employee.personal;' for user2"
+      },
+      "userAttributes": { "user1": { "dept": "engg" }, "user2": { "dept": "r&d" } },
+      "dataMaskResult": { "additionalInfo": { "maskType": "CUSTOM", "maskCondition":null, "maskedValue": "CASE WHEN dept = 'r&d' THEN {col} ELSE mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1') END"}, "policyId": 101}
+    },
+    { "name": "'select ssn from employee.personal;' for user1 - filterExpr=dept='engg'",
+      "request": {
+        "resource": { "elements": { "database": "employee", "table": "personal" } },
+        "accessType": "select", "user": "user1", "userGroups": [], "requestData": "select ssn from employee.personal;' for user1"
+      },
+      "userAttributes": { "user1": { "dept": "engg" }, "user2": { "dept": "r&d" } },
+      "rowFilterResult": { "additionalInfo": { "filterExpr": "dept='engg'" }, "policyId": 201}
+    },
+    { "name": "'select ssn from employee.personal;' for user2 - filterExpr=dept='r&d'",
+      "request": {
+        "resource": { "elements": { "database": "employee", "table": "personal" } },
+        "accessType": "select", "user": "user2", "userGroups": [], "requestData": "select ssn from employee.personal;' for user2"
+      },
+      "userAttributes": { "user1": { "dept": "engg" }, "user2": { "dept": "r&d" } },
+      "rowFilterResult": { "additionalInfo": { "filterExpr": "dept='r&d'" }, "policyId": 201}
+    }
+  ]
+}
+