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 2021/12/21 01:48:28 UTC
[ranger] 02/02: RANGER-3550: enhancement to support use of user/tag attributes in row-filter/condition expressions
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch ranger-2.3
in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 52a855892fab138652255b9f492c06725c82d7be
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Sun Nov 28 16:59:27 2021 -0800
RANGER-3550: enhancement to support use of user/tag attributes in row-filter/condition expressions
(cherry picked from commit e198d01e3c23b89c9fdbcb2915931a4714185b4e)
---
.../RangerScriptConditionEvaluator.java | 12 +-
.../policyengine/RangerRequestScriptEvaluator.java | 20 +--
.../RangerDefaultRowFilterPolicyItemEvaluator.java | 30 +++-
.../ranger/plugin/util/RangerCommonConstants.java | 6 +-
.../plugin/util/RangerRequestExprResolver.java | 88 +++++++++++
.../ranger/plugin/util/ScriptEngineUtil.java | 2 +-
.../RangerCustomConditionMatcherTest.java | 35 ++++-
.../RangerRequestScriptEvaluatorTest.java | 35 +++--
.../plugin/util/RangerRequestExprResolverTest.java | 170 +++++++++++++++++++++
9 files changed, 357 insertions(+), 41 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
index b94225b..2b6b75f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerScriptConditionEvaluator.java
@@ -38,7 +38,7 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
private static final Log LOG = LogFactory.getLog(RangerScriptConditionEvaluator.class);
private ScriptEngine scriptEngine;
- private boolean enableJsonCtx = false;
+ private Boolean enableJsonCtx = null;
@Override
public void init() {
@@ -54,7 +54,11 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
if (MapUtils.isNotEmpty(evalOptions)) {
engineName = evalOptions.get("engineName");
- enableJsonCtx = Boolean.parseBoolean(evalOptions.getOrDefault(SCRIPT_OPTION_ENABLE_JSON_CTX, Boolean.toString(enableJsonCtx)));
+ String strEnableJsonCtx = evalOptions.get(SCRIPT_OPTION_ENABLE_JSON_CTX);
+
+ if (StringUtils.isNotEmpty(strEnableJsonCtx)) {
+ enableJsonCtx = Boolean.parseBoolean(strEnableJsonCtx);
+ }
}
if (StringUtils.isBlank(engineName)) {
@@ -98,6 +102,10 @@ public class RangerScriptConditionEvaluator extends RangerAbstractConditionEvalu
RangerRequestScriptEvaluator evaluator = new RangerRequestScriptEvaluator(request);
+ if (enableJsonCtx == null) { // if not specified in evaluatorOptions, set it on first call to isMatched()
+ enableJsonCtx = RangerRequestScriptEvaluator.needsJsonCtxEnabled(script);
+ }
+
evaluator.evaluateConditionScript(scriptEngine, script, enableJsonCtx);
result = evaluator.getResult();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
index 64f01c9..d99a7d5 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
@@ -69,10 +69,10 @@ public final class RangerRequestScriptEvaluator {
SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_REQUEST + ";" +
SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_RESOURCE + ";" +
SCRIPT_VAR_USER + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ATTRIBUTES + ";" +
- SCRIPT_VAR_UGROUPS + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" +
- SCRIPT_VAR_UGROUP + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" +
+ SCRIPT_VAR_UGNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUPS + ";" +
+ SCRIPT_VAR_UG + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_GROUP_ATTRIBUTES + ";" +
SCRIPT_VAR_UGA + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_UGA + ";" +
- SCRIPT_VAR_UROLES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" +
+ SCRIPT_VAR_URNAMES + "=" + SCRIPT_VAR_REQ + "." + SCRIPT_FIELD_USER_ROLES + ";" +
SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" +
SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" +
SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";";
@@ -262,11 +262,11 @@ public final class RangerRequestScriptEvaluator {
Set<RangerTagForEval> requestTags = RangerAccessRequestUtil.getRequestTagsFromContext(getRequestContext());
if (CollectionUtils.isNotEmpty(requestTags)) {
- Set<Map<String, Object>> tags = new HashSet<>();
- Set<String> tagNames = new HashSet<>();
+ Map<String, Map<String, Object>> tags = new HashMap();
+ Set<String> tagNames = new HashSet<>();
for (RangerTagForEval tag : requestTags) {
- tags.add(toMap(tag));
+ tags.put(tag.getType(), toMap(tag));
tagNames.add(tag.getType());
}
@@ -279,7 +279,7 @@ public final class RangerRequestScriptEvaluator {
ret.put(SCRIPT_FIELD_TAG, toMap(currentTag));
}
} else {
- ret.put(SCRIPT_FIELD_TAGS, Collections.emptySet());
+ ret.put(SCRIPT_FIELD_TAGS, Collections.emptyMap());
ret.put(SCRIPT_FIELD_TAG_NAMES, Collections.emptySet());
}
@@ -659,9 +659,9 @@ public final class RangerRequestScriptEvaluator {
varNames.add(SCRIPT_VAR_TAGNAMES);
varNames.add(SCRIPT_VAR_TAGS);
varNames.add(SCRIPT_VAR_UGA);
- varNames.add(SCRIPT_VAR_UGROUP);
- varNames.add(SCRIPT_VAR_UGROUPS);
- varNames.add(SCRIPT_VAR_UROLES);
+ varNames.add(SCRIPT_VAR_UG);
+ varNames.add(SCRIPT_VAR_UGNAMES);
+ varNames.add(SCRIPT_VAR_URNAMES);
varNames.add(SCRIPT_VAR_USER);
return ".*(" + StringUtils.join(varNames, '|') + ").*";
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultRowFilterPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultRowFilterPolicyItemEvaluator.java
index 0831dde..841fee3 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultRowFilterPolicyItemEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultRowFilterPolicyItemEvaluator.java
@@ -25,15 +25,32 @@ import org.apache.ranger.plugin.model.RangerServiceDef;
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 RangerDefaultRowFilterPolicyItemEvaluator extends RangerDefaultPolicyItemEvaluator implements RangerRowFilterPolicyItemEvaluator {
final private RangerRowFilterPolicyItem rowFilterPolicyItem;
+ final private String rowFilterExpr;
+ final private RangerRequestExprResolver exprResolver;
public RangerDefaultRowFilterPolicyItemEvaluator(RangerServiceDef serviceDef, RangerPolicy policy, RangerRowFilterPolicyItem policyItem, int policyItemIndex, RangerPolicyEngineOptions options) {
super(serviceDef, policy, policyItem, RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_DATAMASK, policyItemIndex, options);
rowFilterPolicyItem = policyItem;
+
+ RangerPolicyItemRowFilterInfo rowFilterInfo = getRowFilterInfo();
+
+ if (rowFilterInfo != null && rowFilterInfo.getFilterExpr() != null) {
+ rowFilterExpr = rowFilterInfo.getFilterExpr();
+ } else {
+ rowFilterExpr = null;
+ }
+
+ if (rowFilterExpr != null && RangerRequestExprResolver.hasExpressions(rowFilterExpr)) {
+ exprResolver = new RangerRequestExprResolver(rowFilterExpr, getServiceType());
+ } else {
+ exprResolver = null;
+ }
}
@Override
@@ -43,11 +60,16 @@ public class RangerDefaultRowFilterPolicyItemEvaluator extends RangerDefaultPoli
@Override
public void updateAccessResult(RangerPolicyEvaluator policyEvaluator, RangerAccessResult result, RangerPolicyResourceMatcher.MatchType matchType) {
- RangerPolicyItemRowFilterInfo rowFilterInfo = getRowFilterInfo();
+ if (result.getFilterExpr() == null) {
+ if (exprResolver != null) {
+ result.setFilterExpr(exprResolver.resolveExpressions(result.getAccessRequest()));
+ } else if (rowFilterExpr != null) {
+ result.setFilterExpr(rowFilterExpr);
+ }
- if (result.getFilterExpr() == null && rowFilterInfo != null) {
- result.setFilterExpr(rowFilterInfo.getFilterExpr());
- policyEvaluator.updateAccessResult(result, matchType, true, getComments());
+ if (result.getFilterExpr() != null) {
+ policyEvaluator.updateAccessResult(result, matchType, true, getComments());
+ }
}
}
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
index 63bed50..4152170 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerCommonConstants.java
@@ -63,9 +63,9 @@ public class RangerCommonConstants {
public static final String SCRIPT_VAR_TAGNAMES = "TAGNAMES";
public static final String SCRIPT_VAR_TAGS = "TAGS";
public static final String SCRIPT_VAR_UGA = "UGA";
- public static final String SCRIPT_VAR_UGROUP = "UGROUP";
- public static final String SCRIPT_VAR_UGROUPS = "UGROUPS";
- public static final String SCRIPT_VAR_UROLES = "UROLES";
+ public static final String SCRIPT_VAR_UG = "UG";
+ public static final String SCRIPT_VAR_UGNAMES = "UGNAMES";
+ public static final String SCRIPT_VAR_URNAMES = "URNAMES";
public static final String SCRIPT_VAR_USER = "USER";
public static final String SCRIPT_FIELD_ACCESS_TIME = "accessTime";
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
new file mode 100644
index 0000000..d70430b
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
+
+import javax.script.ScriptEngine;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class RangerRequestExprResolver {
+ private static final Log LOG = LogFactory.getLog(RangerRequestExprResolver.class);
+
+ private static final String REGEX_GROUP_EXPR = "expr";
+ private static final String SCRIPT_ENGINE_NAME = "JavaScript";
+ private static final Pattern PATTERN = Pattern.compile("\\$\\{\\{(?<" + REGEX_GROUP_EXPR + ">.*?)\\}\\}");
+
+ private final String str;
+ private final String serviceType;
+ private final boolean hasTokens;
+
+
+ public RangerRequestExprResolver(String str, String serviceType) {
+ this.str = str;
+ this.serviceType = serviceType;
+ this.hasTokens = hasExpressions(str);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("RangerRequestExprResolver(" + str + "): hasTokens=" + hasTokens);
+ }
+ }
+
+ public String resolveExpressions(RangerAccessRequest request) {
+ String ret = str;
+
+ if (hasTokens) {
+ RangerRequestScriptEvaluator scriptEvaluator = new RangerRequestScriptEvaluator(request);
+ ScriptEngine scriptEngine = ScriptEngineUtil.createScriptEngine(SCRIPT_ENGINE_NAME, serviceType);
+ StringBuffer sb = new StringBuffer();
+ Matcher matcher = PATTERN.matcher(str);
+
+ while (matcher.find()) {
+ String expr = matcher.group(REGEX_GROUP_EXPR);
+ String val = Objects.toString(scriptEvaluator.evaluateScript(scriptEngine, expr));
+
+ matcher.appendReplacement(sb, val);
+ }
+
+ matcher.appendTail(sb);
+
+ ret = sb.toString();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("RangerRequestExprResolver.processExpressions(" + str + "): ret=" + ret);
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasExpressions(String str) {
+ Matcher matcher = PATTERN.matcher(str);
+
+ return matcher.find();
+ }
+}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
index b0782ec..983c578 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ScriptEngineUtil.java
@@ -58,7 +58,7 @@ public class ScriptEngineUtil {
LOG.error("RangerScriptConditionEvaluator.init() failed with exception=" + exp);
}
- if (ret == null) {
+ if (ret == null && serviceType != null) {
LOG.warn("failed to initialize script engine '" + engineName + "' in a default manner." +
" Will try to get script-engine from plugin-class-loader");
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
index d5f1564..5b98574 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerCustomConditionMatcherTest.java
@@ -30,6 +30,7 @@ import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
+import org.apache.ranger.plugin.util.RangerUserStore;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -75,11 +76,11 @@ public class RangerCustomConditionMatcherTest {
RangerScriptConditionEvaluator userGroup1Attr2Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group1']['attr2'].equals('test-group1-value2')");
RangerScriptConditionEvaluator userGroup2Attr1Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group2']['attr1'].equals('test-group2-value1')");
RangerScriptConditionEvaluator userGroup2Attr2Condition = createScriptConditionEvaluator("_ctx.request.userGroupAttributes['test-group2']['attr2'].equals('test-group2-value2')");
- RangerScriptConditionEvaluator tagsLengthCondition = createScriptConditionEvaluator("_ctx.tags.length == 2");
+ RangerScriptConditionEvaluator tagsLengthCondition = createScriptConditionEvaluator("Object.keys(_ctx.tags).length == 2");
RangerScriptConditionEvaluator tagTypeCondition = createScriptConditionEvaluator("_ctx.tag._type.equals('PCI')");
RangerScriptConditionEvaluator tagAttributesCondition = createScriptConditionEvaluator("_ctx.tag.attr1.equals('PCI_value')");
- RangerScriptConditionEvaluator tagsTypeCondition = createScriptConditionEvaluator("switch(_ctx.tags[0]._type) { case 'PCI': _ctx.tags[1]._type.equals('PII'); break; case 'PII': _ctx.tags[1]._type.equals('PCI'); break; default: false; }");
- RangerScriptConditionEvaluator tagsAttributesCondition = createScriptConditionEvaluator("switch(_ctx.tags[0]._type) { case 'PCI': _ctx.tags[0].attr1.equals('PCI_value') && _ctx.tags[1].attr1.equals('PII_value'); break; case 'PII': _ctx.tags[0].attr1.equals('PII_value') && _ctx.tags[1].attr1.equals('PCI_value'); break; default: false; }");
+ RangerScriptConditionEvaluator tagsTypeCondition = createScriptConditionEvaluator("_ctx.tags['PII']._type == 'PII' && _ctx.tags['PCI']._type == 'PCI'");
+ RangerScriptConditionEvaluator tagsAttributesCondition = createScriptConditionEvaluator("_ctx.tags['PII'].attr1.equals('PII_value') && _ctx.tags['PCI'].attr1.equals('PCI_value')");
Assert.assertTrue("request.resource.database should be db1", resourceDbCondition.isMatched(request));
Assert.assertTrue("request.resource.database should not be db2", resourceDbCondition2.isMatched(request));
@@ -265,8 +266,8 @@ public class RangerCustomConditionMatcherTest {
request.setAccessType("select");
request.setAction("query");
request.setUser("test-user");
- request.setUserGroups(Collections.singleton("test-group"));
- request.setUserRoles(Collections.singleton("test-role"));
+ request.setUserGroups(new HashSet<>(Arrays.asList("test-group1", "test-group2")));
+ request.setUserRoles(new HashSet<>(Arrays.asList("test-role1", "test-role2")));
if (resourceTags != null) {
Set<RangerTagForEval> rangerTagForEvals = new HashSet<>();
@@ -289,6 +290,30 @@ public class RangerCustomConditionMatcherTest {
RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), null);
}
+ Map<String, Map<String, String>> userAttrMapping = new HashMap<>();
+ Map<String, Map<String, String>> groupAttrMapping = new HashMap<>();
+ Map<String, String> testUserAttrs = new HashMap<>();
+ Map<String, String> testGroup1Attrs = new HashMap<>();
+ Map<String, String> testGroup2Attrs = new HashMap<>();
+
+ testUserAttrs.put("attr1", "test-user-value1");
+ testUserAttrs.put("attr2", "test-user-value2");
+ testGroup1Attrs.put("attr1", "test-group1-value1");
+ testGroup1Attrs.put("attr2", "test-group1-value2");
+ testGroup2Attrs.put("attr1", "test-group2-value1");
+ testGroup2Attrs.put("attr2", "test-group2-value2");
+
+ userAttrMapping.put("test-user", testUserAttrs);
+ groupAttrMapping.put("test-group1", testGroup1Attrs);
+ groupAttrMapping.put("test-group2", testGroup2Attrs);
+
+ RangerUserStore userStore = mock(RangerUserStore.class);
+
+ when(userStore.getUserAttrMapping()).thenReturn(userAttrMapping);
+ when(userStore.getGroupAttrMapping()).thenReturn(groupAttrMapping);
+
+ RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
+
return request;
}
}
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java
index 798da05..ff638b2 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerRequestScriptEvaluatorTest.java
@@ -59,19 +59,20 @@ public class RangerRequestScriptEvaluatorTest {
Assert.assertTrue("test: USER['state'] is 'CA'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER['state'] == 'CA'"));
Assert.assertTrue("test: USER.state is 'CA'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER.state == 'CA'"));
- Assert.assertTrue("test: UGROUPS has test-group1", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group1') != -1"));
- Assert.assertTrue("test: UGROUPS has test-group2", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group2') != -1"));
- Assert.assertTrue("test: UGROUPS doesn't have test-group3", (Boolean)evaluator.evaluateScript(scriptEngine, "UGROUPS.indexOf('test-group3') == -1"));
- Assert.assertTrue("test: UGROUP['test-group1'].dept is 'ENGG'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].dept == 'ENGG'"));
- Assert.assertTrue("test: UGROUP['test-group1'].site is 10", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].site == 10"));
- Assert.assertTrue("test: UGROUP['test-group2'].dept is 'PROD'", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group2'].dept == 'PROD'"));
- Assert.assertTrue("test: UGROUP['test-group2'].site is 20", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group2'].site == 20"));
- Assert.assertTrue("test: UGROUP['test-group3'] is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group3'] == null"));
- Assert.assertTrue("test: UGROUP['test-group1'].notExists is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UGROUP['test-group1'].notExists == null"));
-
- Assert.assertTrue("test: UROLES has test-role1", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role1') != -1"));
- Assert.assertTrue("test: UROLES has test-role2", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role2') != -1"));
- Assert.assertTrue("test: UROLES doesn't have test-role3", (Boolean)evaluator.evaluateScript(scriptEngine, "UROLES.indexOf('test-role3') == -1"));
+ Assert.assertTrue("test: UGNAMES has test-group1", (Boolean)evaluator.evaluateScript(scriptEngine, "UGNAMES.indexOf('test-group1') != -1"));
+ Assert.assertTrue("test: UGNAMES has test-group2", (Boolean)evaluator.evaluateScript(scriptEngine, "UGNAMES.indexOf('test-group2') != -1"));
+ Assert.assertTrue("test: UGNAMES doesn't have test-group3", (Boolean)evaluator.evaluateScript(scriptEngine, "UGNAMES.indexOf('test-group3') == -1"));
+
+ Assert.assertTrue("test: UG['test-group1'].dept is 'ENGG'", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group1'].dept == 'ENGG'"));
+ Assert.assertTrue("test: UG['test-group1'].site is 10", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group1'].site == 10"));
+ Assert.assertTrue("test: UG['test-group2'].dept is 'PROD'", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group2'].dept == 'PROD'"));
+ Assert.assertTrue("test: UG['test-group2'].site is 20", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group2'].site == 20"));
+ Assert.assertTrue("test: UG['test-group3'] is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group3'] == null"));
+ Assert.assertTrue("test: UG['test-group1'].notExists is null", (Boolean) evaluator.evaluateScript(scriptEngine, "UG['test-group1'].notExists == null"));
+
+ Assert.assertTrue("test: URNAMES has test-role1", (Boolean)evaluator.evaluateScript(scriptEngine, "URNAMES.indexOf('test-role1') != -1"));
+ Assert.assertTrue("test: URNAMES has test-role2", (Boolean)evaluator.evaluateScript(scriptEngine, "URNAMES.indexOf('test-role2') != -1"));
+ Assert.assertTrue("test: URNAMES doesn't have test-role3", (Boolean)evaluator.evaluateScript(scriptEngine, "URNAMES.indexOf('test-role3') == -1"));
Assert.assertTrue("test: UGA.sVal['dept'] is 'ENGG'", (Boolean)evaluator.evaluateScript(scriptEngine, "UGA.sVal['dept'] == 'ENGG'"));
Assert.assertTrue("test: UGA.sVal['site'] is 10", (Boolean) evaluator.evaluateScript(scriptEngine, "UGA.sVal['site'] == 10"));
@@ -93,9 +94,11 @@ public class RangerRequestScriptEvaluatorTest {
Assert.assertTrue("test: TAG._type is 'PII'", (Boolean) evaluator.evaluateScript(scriptEngine, "TAG._type == 'PII'"));
Assert.assertTrue("test: TAG.attr1 is 'PII_value'", (Boolean) evaluator.evaluateScript(scriptEngine, "TAG.attr1 == 'PII_value'"));
- Assert.assertTrue("test: TAGS.length is 2", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS.length == 2"));
- Assert.assertTrue("test: TAGS has PII and PCI", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS[0]._type == 'PCI' ? TAGS[1]._type == 'PII' : TAGS[0]._type == 'PII' && TAGS[1]._type == 'PCI'"));
- Assert.assertTrue("test: TAGS has PII.attr1=PII_value and PCI.attr1=PCI_value", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGS[0]._type == 'PCI' ? (TAGS[0].attr1 == 'PCI_value' && TAGS[1].attr1 == 'PII_value') : (TAGS[0].attr1 == 'PII_value' && TAGS[1].attr1 == 'PCI_value')"));
+ Assert.assertTrue("test: TAGS.length is 2", (Boolean) evaluator.evaluateScript(scriptEngine, "Object.keys(TAGS).length == 2"));
+ Assert.assertEquals("test: TAGS has PII", evaluator.evaluateScript(scriptEngine, "TAGS.PII._type"), "PII");
+ Assert.assertEquals("test: TAGS has PCI", evaluator.evaluateScript(scriptEngine, "TAGS.PCI._type"), "PCI");
+ Assert.assertEquals("test: TAGS has PII.attr1=PII_value", evaluator.evaluateScript(scriptEngine, "TAGS['PII'].attr1"), "PII_value");
+ Assert.assertEquals("test: TAGS has PCI.attr1=PCI_value", evaluator.evaluateScript(scriptEngine, "TAGS['PCI'].attr1"), "PCI_value");
Assert.assertTrue("test: TAGNAMES.length is 2", (Boolean) evaluator.evaluateScript(scriptEngine, "TAGNAMES.length == 2"));
Assert.assertTrue("test: TAGNAMES has 'PII'", (Boolean)evaluator.evaluateScript(scriptEngine, "TAGNAMES.indexOf('PII') != -1"));
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/util/RangerRequestExprResolverTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/util/RangerRequestExprResolverTest.java
new file mode 100644
index 0000000..6d5edc0
--- /dev/null
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/util/RangerRequestExprResolverTest.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
+import org.apache.ranger.plugin.model.RangerTag;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.*;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RangerRequestExprResolverTest {
+ @Test
+ public void testRequestAttributes() {
+ RangerAccessRequest request = createRequest(Arrays.asList("PII", "PCI"));
+
+ Map<String, String> exprValue = new HashMap<>();
+
+ exprValue.put("s3://mybucket/users/${{USER._name}}/${{USER.state}}/test.txt", "s3://mybucket/users/test-user/CA/test.txt");
+ exprValue.put("state == '${{USER.state}}' AND dept == '${{UGA.sVal.dept}}'", "state == 'CA' AND dept == 'ENGG'");
+ exprValue.put("attr1 == '${{TAG.attr1}}'", "attr1 == 'PII_value'");
+
+ exprValue.put("${{USER._name}}", "test-user");
+ exprValue.put("${{USER['state']}}", "CA");
+ exprValue.put("${{USER.state}}", "CA");
+
+ exprValue.put("${{UGNAMES.indexOf('test-group1') != -1}}", "true");
+ exprValue.put("${{UGNAMES.indexOf('test-group2') != -1}}", "true");
+ exprValue.put("${{UGNAMES.indexOf('test-group3') == -1}}", "true");
+
+ exprValue.put("${{UG['test-group1'].dept}}", "ENGG");
+ exprValue.put("${{UG['test-group1'].site}}", "10");
+ exprValue.put("${{UG['test-group2'].dept}}", "PROD");
+ exprValue.put("${{UG['test-group2'].site}}", "20");
+ exprValue.put("${{UG['test-group3']}}", "null");
+ exprValue.put("${{UG['test-group1'].notExists}}", "null");
+
+ exprValue.put("${{URNAMES.indexOf('test-role1') != -1}}", "true");
+ exprValue.put("${{URNAMES.indexOf('test-role2') != -1}}", "true");
+ exprValue.put("${{URNAMES.indexOf('test-role3') == -1}}", "true");
+
+ exprValue.put("${{UGA.sVal.dept}}", "ENGG");
+ exprValue.put("${{UGA.sVal.site}}", "10");
+ exprValue.put("${{UGA.sVal.notExists}}", "null");
+ exprValue.put("${{J(UGA.mVal.dept)}}", "[\"ENGG\",\"PROD\"]");
+ exprValue.put("${{J(UGA.mVal.site)}}", "[\"10\",\"20\"]");
+ exprValue.put("${{J(UGA.mVal.notExists)}}", "null");
+ exprValue.put("${{UGA.mVal['dept'].indexOf('ENGG') != -1}}", "true");
+ exprValue.put("${{UGA.mVal['dept'].indexOf('PROD') != -1}}", "true");
+ exprValue.put("${{UGA.mVal['dept'].indexOf('EXEC') == -1}}", "true");
+
+ exprValue.put("${{REQ.accessType}}", "select");
+ exprValue.put("${{REQ.action}}", "query");
+
+ exprValue.put("${{RES._ownerUser}}", "testUser");
+ exprValue.put("${{RES.database}}", "db1");
+ exprValue.put("${{RES.table}}", "tbl1");
+ exprValue.put("${{RES.column}}", "col1");
+
+ exprValue.put("${{TAG._type}}", "PII");
+ exprValue.put("${{TAG.attr1}}", "PII_value");
+ exprValue.put("${{Object.keys(TAGS).length}}", "2");
+ exprValue.put("${{TAGS.PCI._type}}", "PCI");
+ exprValue.put("${{TAGS.PCI.attr1}}", "PCI_value");
+ exprValue.put("${{TAGS.PII._type}}", "PII");
+ exprValue.put("${{TAGS.PII.attr1}}", "PII_value");
+
+ exprValue.put("${{TAGNAMES.length}}", "2");
+ exprValue.put("${{TAGNAMES.indexOf('PII') != -1}}", "true");
+ exprValue.put("${{TAGNAMES.indexOf('PCI') != -1}}", "true");
+
+ for (Map.Entry<String, String> entry : exprValue.entrySet()) {
+ String expr = entry.getKey();
+ String value = entry.getValue();
+ RangerRequestExprResolver resolver = new RangerRequestExprResolver(expr, null);
+ String resolvedVal = resolver.resolveExpressions(request);
+
+ Assert.assertEquals(expr, value, resolvedVal);
+ }
+ }
+
+
+ RangerAccessRequest createRequest(List<String> resourceTags) {
+ RangerAccessResource resource = mock(RangerAccessResource.class);
+
+ Map<String, Object> resourceMap = new HashMap<>();
+
+ resourceMap.put("database", "db1");
+ resourceMap.put("table", "tbl1");
+ resourceMap.put("column", "col1");
+
+ when(resource.getAsString()).thenReturn("db1/tbl1/col1");
+ when(resource.getOwnerUser()).thenReturn("testUser");
+ when(resource.getAsMap()).thenReturn(resourceMap);
+ when(resource.getReadOnlyCopy()).thenReturn(resource);
+
+ RangerAccessRequestImpl request = new RangerAccessRequestImpl();
+
+ request.setResource(resource);
+ request.setResourceMatchingScope(RangerAccessRequest.ResourceMatchingScope.SELF);
+ request.setAccessType("select");
+ request.setAction("query");
+ request.setUser("test-user");
+ request.setUserGroups(new HashSet<>(Arrays.asList("test-group1", "test-group2")));
+ request.setUserRoles(new HashSet<>(Arrays.asList("test-role1", "test-role2")));
+
+ RangerAccessRequestUtil.setCurrentResourceInContext(request.getContext(), resource);
+
+ if (resourceTags != null) {
+ Set<RangerTagForEval> rangerTagForEvals = new HashSet<>();
+ RangerTagForEval currentTag = null;
+
+ for (String resourceTag : resourceTags) {
+ RangerTag tag = new RangerTag(UUID.randomUUID().toString(), resourceTag, Collections.singletonMap("attr1", resourceTag + "_value"), null, null, null);
+ RangerTagForEval tagForEval = new RangerTagForEval(tag, RangerPolicyResourceMatcher.MatchType.SELF);
+
+ rangerTagForEvals.add(tagForEval);
+
+ if (currentTag == null) {
+ currentTag = tagForEval;
+ }
+ }
+
+ RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), rangerTagForEvals);
+ RangerAccessRequestUtil.setCurrentTagInContext(request.getContext(), currentTag);
+ } else {
+ RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), null);
+ }
+
+ RangerUserStore userStore = mock(RangerUserStore.class);
+
+ RangerAccessRequestUtil.setRequestUserStoreInContext(request.getContext(), userStore);
+
+ Map<String, Map<String, String>> userAttrMapping = Collections.singletonMap("test-user", Collections.singletonMap("state", "CA"));
+ Map<String, Map<String, String>> groupAttrMapping = new HashMap<>();
+
+ groupAttrMapping.put("test-group1", new HashMap<String, String>() {{ put("dept", "ENGG"); put("site", "10"); }});
+ groupAttrMapping.put("test-group2", new HashMap<String, String>() {{ put("dept", "PROD"); put("site", "20"); }});
+
+ when(userStore.getUserAttrMapping()).thenReturn(userAttrMapping);
+ when(userStore.getGroupAttrMapping()).thenReturn(groupAttrMapping);
+
+ return request;
+ }
+
+}
\ No newline at end of file