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/02/04 04:05:38 UTC
[ranger] branch master updated: RANGER-3605: added support for macros in row-filter/condition expressions
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 a2e1ec4 RANGER-3605: added support for macros in row-filter/condition expressions
a2e1ec4 is described below
commit a2e1ec4d55d9d87367c5da75763e0a44b5231fcc
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Wed Feb 2 16:56:40 2022 -0800
RANGER-3605: added support for macros in row-filter/condition expressions
---
.../policyengine/RangerRequestScriptEvaluator.java | 36 ++++++++-
.../apache/ranger/plugin/util/MacroProcessor.java | 86 ++++++++++++++++++++++
.../ranger/plugin/util/RangerCommonConstants.java | 17 +++++
.../RangerRequestScriptEvaluatorTest.java | 38 +++++-----
.../ranger/plugin/util/MacroProcessorTest.java | 56 ++++++++++++++
5 files changed, 213 insertions(+), 20 deletions(-)
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 e3ce559..9b72a1b 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
@@ -25,6 +25,7 @@ import org.apache.hadoop.conf.Configuration;
import org.apache.ranger.authorization.utils.JsonUtils;
import org.apache.ranger.authorization.utils.StringUtil;
import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
+import org.apache.ranger.plugin.util.MacroProcessor;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.apache.ranger.plugin.util.RangerPerfTracer;
import org.apache.ranger.plugin.util.RangerUserStore;
@@ -65,11 +66,12 @@ public final class RangerRequestScriptEvaluator {
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 + ";";
-
private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern());
private static final Character CHAR_QUOTE = '\'';
private static final Character CHAR_COMMA = ',';
+ private static final MacroProcessor MACRO_PROCESSOR = new MacroProcessor(getMacrosMap());
+
private static String[] dateFormatStrings = null;
private final RangerAccessRequest accessRequest;
@@ -120,15 +122,23 @@ public final class RangerRequestScriptEvaluator {
return ret;
}
+ public static String expandMacros(String script) {
+ return MACRO_PROCESSOR.expandMacros(script);
+ }
+
public RangerRequestScriptEvaluator(final RangerAccessRequest accessRequest) {
this.accessRequest = accessRequest.getReadOnlyCopy();
}
public Object evaluateScript(ScriptEngine scriptEngine, String script) {
+ script = expandMacros(script);
+
return evaluateScript(scriptEngine, script, needsJsonCtxEnabled(script));
}
public Object evaluateConditionScript(ScriptEngine scriptEngine, String script, boolean enableJsonCtx) {
+ script = expandMacros(script);
+
Object ret = evaluateScript(scriptEngine, script, enableJsonCtx);
if (ret == null) {
@@ -872,6 +882,30 @@ public final class RangerRequestScriptEvaluator {
return ".*(" + StringUtils.join(varNames, '|') + ").*";
}
+ private static Map<String, String> getMacrosMap() {
+ Map<String, String> ret = new HashMap<>();
+
+ ret.put(SCRIPT_MACRO_GET_TAG_ATTR_CSV, "ctx.tagAttrCsv");
+ ret.put(SCRIPT_MACRO_GET_TAG_ATTR_Q_CSV, "ctx.tagAttrCsvQ");
+ ret.put(SCRIPT_MACRO_GET_UG_ATTR_CSV, "ctx.ugAttrCsv");
+ ret.put(SCRIPT_MACRO_GET_UG_ATTR_Q_CSV, "ctx.ugAttrCsvQ");
+ ret.put(SCRIPT_MACRO_TAG_ATTR_NAMES_CSV, "ctx.tagAttrNamesCsv()");
+ ret.put(SCRIPT_MACRO_TAG_ATTR_NAMES_Q_CSV, "ctx.tagAttrNamesCsvQ()");
+ ret.put(SCRIPT_MACRO_TAG_NAMES_CSV, "ctx.tagNamesCsv()");
+ ret.put(SCRIPT_MACRO_TAG_NAMES_Q_CSV, "ctx.tagNamesCsvQ()");
+ ret.put(SCRIPT_MACRO_UG_ATTR_NAMES_CSV, "ctx.ugAttrNamesCsv()");
+ ret.put(SCRIPT_MACRO_UG_ATTR_NAMES_Q_CSV, "ctx.ugAttrNamesCsvQ()");
+ ret.put(SCRIPT_MACRO_UG_NAMES_CSV, "ctx.ugNamesCsv()");
+ ret.put(SCRIPT_MACRO_UG_NAMES_Q_CSV, "ctx.ugNamesCsvQ()");
+ ret.put(SCRIPT_MACRO_UR_NAMES_CSV, "ctx.urNamesCsv()");
+ ret.put(SCRIPT_MACRO_UR_NAMES_Q_CSV, "ctx.urNamesCsvQ()");
+ ret.put(SCRIPT_MACRO_USER_ATTR_NAMES_CSV, "ctx.userAttrNamesCsv()");
+ ret.put(SCRIPT_MACRO_USER_ATTR_NAMES_Q_CSV, "ctx.userAttrNamesCsvQ()");
+
+ return ret;
+ }
+
+
public void logDebug(Object msg) {
LOG.debug(Objects.toString(msg));
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/MacroProcessor.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/MacroProcessor.java
new file mode 100644
index 0000000..7709133
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/MacroProcessor.java
@@ -0,0 +1,86 @@
+/*
+ * 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class MacroProcessor {
+ private static final Logger LOG = LoggerFactory.getLogger(MacroProcessor.class);
+
+ private final Map<String, String> macrosMap;
+ private final Pattern macrosPattern;
+
+ public MacroProcessor(Map<String, String> macrosMap) {
+ this.macrosMap = macrosMap;
+ this.macrosPattern = getMacrosPattern(this.macrosMap);
+ }
+
+ public String expandMacros(String expr) {
+ StringBuffer ret = null;
+ Matcher matcher = macrosPattern.matcher(expr);
+
+ while (matcher.find()) {
+ if (ret == null) {
+ ret = new StringBuffer();
+ }
+
+ String keyword = matcher.group();
+ String replacer = macrosMap.get(keyword);
+
+ matcher.appendReplacement(ret, replacer);
+ }
+
+ if (ret == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("expandMacros({}): no match found!", expr);
+ }
+
+ return expr;
+ } else {
+ matcher.appendTail(ret);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("expandMacros({}): match found. ret={}", expr, ret);
+ }
+
+ return ret.toString();
+ }
+ }
+
+ private Pattern getMacrosPattern(Map<String, String> macros) {
+ StringBuilder sb = new StringBuilder();
+ String sep = "\\b(";
+
+ for (String macro : macros.keySet()) {
+ sb.append(sep).append(macro);
+
+ sep = "|";
+ }
+
+ sb.append(")\\b");
+
+ return Pattern.compile(sb.toString());
+ }
+}
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 ab0e3b7..c98cce0 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
@@ -98,4 +98,21 @@ public class RangerCommonConstants {
public static final String SCRIPT_FIELD_USER_GROUP_ATTRIBUTES = "userGroupAttributes";
public static final String SCRIPT_FIELD_UGA = "uga";
public static final String SCRIPT_FIELD_USER_ROLES = "userRoles";
+
+ public static final String SCRIPT_MACRO_GET_TAG_ATTR_CSV = "GET_TAG_ATTR_CSV";
+ public static final String SCRIPT_MACRO_GET_TAG_ATTR_Q_CSV = "GET_TAG_ATTR_Q_CSV";
+ public static final String SCRIPT_MACRO_GET_UG_ATTR_CSV = "GET_UG_ATTR_CSV";
+ public static final String SCRIPT_MACRO_GET_UG_ATTR_Q_CSV = "GET_UG_ATTR_Q_CSV";
+ public static final String SCRIPT_MACRO_TAG_ATTR_NAMES_CSV = "TAG_ATTR_NAMES_CSV";
+ public static final String SCRIPT_MACRO_TAG_ATTR_NAMES_Q_CSV = "TAG_ATTR_NAMES_Q_CSV";
+ public static final String SCRIPT_MACRO_TAG_NAMES_CSV = "TAG_NAMES_CSV";
+ public static final String SCRIPT_MACRO_TAG_NAMES_Q_CSV = "TAG_NAMES_Q_CSV";
+ public static final String SCRIPT_MACRO_UG_ATTR_NAMES_CSV = "UG_ATTR_NAMES_CSV";
+ public static final String SCRIPT_MACRO_UG_ATTR_NAMES_Q_CSV = "UG_ATTR_NAMES_Q_CSV";
+ public static final String SCRIPT_MACRO_UG_NAMES_CSV = "UG_NAMES_CSV";
+ public static final String SCRIPT_MACRO_UG_NAMES_Q_CSV = "UG_NAMES_Q_CSV";
+ public static final String SCRIPT_MACRO_UR_NAMES_CSV = "UR_NAMES_CSV";
+ public static final String SCRIPT_MACRO_UR_NAMES_Q_CSV = "UR_NAMES_Q_CSV";
+ public static final String SCRIPT_MACRO_USER_ATTR_NAMES_CSV = "USER_ATTR_NAMES_CSV";
+ public static final String SCRIPT_MACRO_USER_ATTR_NAMES_Q_CSV = "USER_ATTR_NAMES_Q_CSV";
}
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 2a0b027..7bbad78 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
@@ -55,25 +55,25 @@ public class RangerRequestScriptEvaluatorTest {
RangerAccessRequest request = createRequest(Arrays.asList("PII", "PCI"));
RangerRequestScriptEvaluator evaluator = new RangerRequestScriptEvaluator(request);
- Assert.assertEquals("test: ctx.ugNamesCsv()", "test-group1,test-group2", evaluator.evaluateScript(scriptEngine, "ctx.ugNamesCsv()"));
- Assert.assertEquals("test: ctx.urNamesCsv()", "test-role1,test-role2", evaluator.evaluateScript(scriptEngine, "ctx.urNamesCsv()"));
- Assert.assertEquals("test: ctx.tagNamesCsv()", "PCI,PII", evaluator.evaluateScript(scriptEngine, "ctx.tagNamesCsv()"));
- Assert.assertEquals("test: ctx.userAttrNamesCsv()", "state", evaluator.evaluateScript(scriptEngine, "ctx.userAttrNamesCsv()"));
- Assert.assertEquals("test: ctx.ugAttrNamesCsv()", "dept,site", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrNamesCsv()"));
- Assert.assertEquals("test: ctx.tagAttrNamesCsv()", "attr1", evaluator.evaluateScript(scriptEngine, "ctx.tagAttrNamesCsv()"));
- Assert.assertEquals("test: ctx.ugAttrCsv('dept')", "ENGG,PROD", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrCsv('dept')"));
- Assert.assertEquals("test: ctx.ugAttrCsv('site')", "10,20", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrCsv('site')"));
- Assert.assertEquals("test: ctx.tagAttrCsv('attr1')", "PCI_value,PII_value", evaluator.evaluateScript(scriptEngine, "ctx.tagAttrCsv('attr1')"));
-
- Assert.assertEquals("test: ctx.ugNamesCsvQ()", "'test-group1','test-group2'", evaluator.evaluateScript(scriptEngine, "ctx.ugNamesCsvQ()"));
- Assert.assertEquals("test: ctx.urNamesCsvQ()", "'test-role1','test-role2'", evaluator.evaluateScript(scriptEngine, "ctx.urNamesCsvQ()"));
- Assert.assertEquals("test: ctx.tagNamesCsvQ()", "'PCI','PII'", evaluator.evaluateScript(scriptEngine, "ctx.tagNamesCsvQ()"));
- Assert.assertEquals("test: ctx.userAttrNamesCsvQ()", "'state'", evaluator.evaluateScript(scriptEngine, "ctx.userAttrNamesCsvQ()"));
- Assert.assertEquals("test: ctx.ugAttrNamesCsvQ()", "'dept','site'", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrNamesCsvQ()"));
- Assert.assertEquals("test: ctx.tagAttrNamesCsvQ()", "'attr1'", evaluator.evaluateScript(scriptEngine, "ctx.tagAttrNamesCsvQ()"));
- Assert.assertEquals("test: ctx.ugAttrCsvQ('dept')", "'ENGG','PROD'", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrCsvQ('dept')"));
- Assert.assertEquals("test: ctx.ugAttrCsvQ('site')", "'10','20'", evaluator.evaluateScript(scriptEngine, "ctx.ugAttrCsvQ('site')"));
- Assert.assertEquals("test: ctx.tagAttrCsvQ('attr1')", "'PCI_value','PII_value'", evaluator.evaluateScript(scriptEngine, "ctx.tagAttrCsvQ('attr1')"));
+ Assert.assertEquals("test: UG_NAMES_CSV", "test-group1,test-group2", evaluator.evaluateScript(scriptEngine, "UG_NAMES_CSV"));
+ Assert.assertEquals("test: UR_NAMES_CSV", "test-role1,test-role2", evaluator.evaluateScript(scriptEngine, "UR_NAMES_CSV"));
+ Assert.assertEquals("test: TAG_NAMES_CSV", "PCI,PII", evaluator.evaluateScript(scriptEngine, "TAG_NAMES_CSV"));
+ Assert.assertEquals("test: USER_ATTR_NAMES_CSV", "state", evaluator.evaluateScript(scriptEngine, "USER_ATTR_NAMES_CSV"));
+ Assert.assertEquals("test: UG_ATTR_NAMES_CSV", "dept,site", evaluator.evaluateScript(scriptEngine, "UG_ATTR_NAMES_CSV"));
+ Assert.assertEquals("test: TAG_ATTR_NAMES_CSV", "attr1", evaluator.evaluateScript(scriptEngine, "TAG_ATTR_NAMES_CSV"));
+ Assert.assertEquals("test: GET_UG_ATTR_CSV('dept')", "ENGG,PROD", evaluator.evaluateScript(scriptEngine, "GET_UG_ATTR_CSV('dept')"));
+ Assert.assertEquals("test: GET_UG_ATTR_CSV('site')", "10,20", evaluator.evaluateScript(scriptEngine, "GET_UG_ATTR_CSV('site')"));
+ Assert.assertEquals("test: GET_TAG_ATTR_CSV('attr1')", "PCI_value,PII_value", evaluator.evaluateScript(scriptEngine, "GET_TAG_ATTR_CSV('attr1')"));
+
+ Assert.assertEquals("test: UG_NAMES_Q_CSV", "'test-group1','test-group2'", evaluator.evaluateScript(scriptEngine, "UG_NAMES_Q_CSV"));
+ Assert.assertEquals("test: UR_NAMES_Q_CSV", "'test-role1','test-role2'", evaluator.evaluateScript(scriptEngine, "UR_NAMES_Q_CSV"));
+ Assert.assertEquals("test: TAG_NAMES_Q_CSV", "'PCI','PII'", evaluator.evaluateScript(scriptEngine, "TAG_NAMES_Q_CSV"));
+ Assert.assertEquals("test: USER_ATTR_NAMES_Q_CSV", "'state'", evaluator.evaluateScript(scriptEngine, "USER_ATTR_NAMES_Q_CSV"));
+ Assert.assertEquals("test: UG_ATTR_NAMES_Q_CSV", "'dept','site'", evaluator.evaluateScript(scriptEngine, "UG_ATTR_NAMES_Q_CSV"));
+ Assert.assertEquals("test: TAG_ATTR_NAMES_Q_CSV", "'attr1'", evaluator.evaluateScript(scriptEngine, "TAG_ATTR_NAMES_Q_CSV"));
+ Assert.assertEquals("test: GET_UG_ATTR_Q_CSV('dept')", "'ENGG','PROD'", evaluator.evaluateScript(scriptEngine, "GET_UG_ATTR_Q_CSV('dept')"));
+ Assert.assertEquals("test: GET_UG_ATTR_Q_CSV('site')", "'10','20'", evaluator.evaluateScript(scriptEngine, "GET_UG_ATTR_Q_CSV('site')"));
+ Assert.assertEquals("test: GET_TAG_ATTR_Q_CSV('attr1')", "'PCI_value','PII_value'", evaluator.evaluateScript(scriptEngine, "GET_TAG_ATTR_Q_CSV('attr1')"));
Assert.assertTrue("test: USER._name is 'test-user'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER._name == 'test-user'"));
Assert.assertTrue("test: USER['state'] is 'CA'", (Boolean) evaluator.evaluateScript(scriptEngine, "USER['state'] == 'CA'"));
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/util/MacroProcessorTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/util/MacroProcessorTest.java
new file mode 100644
index 0000000..7573c7f
--- /dev/null
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/util/MacroProcessorTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+public class MacroProcessorTest {
+
+ @Test
+ public void testMacros() {
+ Map<String, String> macros = new HashMap<>();
+
+ macros.put("USER", "getUser()");
+ macros.put("USER_NAME", "getUserName()");
+ macros.put("GROUPS", "getGroups()");
+ macros.put("GET_GROUP_ATTR", "getGroupAttr");
+
+ MacroProcessor processor = new MacroProcessor(macros);
+
+ Map<String, String> testInputOutput = new HashMap<>();
+
+ testInputOutput.putAll(macros);
+ testInputOutput.put("USER != null", "getUser() != null");
+ testInputOutput.put("USER_NAME=='testUser'", "getUserName()=='testUser'");
+ testInputOutput.put("USER != null && USER_NAME=='testUser'", "getUser() != null && getUserName()=='testUser'");
+ testInputOutput.put("GROUPS.length() > 1", "getGroups().length() > 1");
+ testInputOutput.put("GET_GROUP_ATTR('group1', 'attr1')", "getGroupAttr('group1', 'attr1')");
+
+ for (Map.Entry<String, String> inputOutput : testInputOutput.entrySet()) {
+ String input = inputOutput.getKey();
+ String output = inputOutput.getValue();
+
+ assertEquals(output, processor.expandMacros(input));;
+ }
+ }
+}