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 1438644b7 RANGER-4234: simplify condition/row-filter expressions that 
deal with delimited strings
1438644b7 is described below

commit 1438644b7f1f7f5fb9e62d0d855982d7e10e7fc6
Author: Eckman, Barbara <[email protected]>
AuthorDate: Fri Sep 22 11:38:07 2023 -0400

    RANGER-4234: simplify condition/row-filter expressions that deal with 
delimited strings
    
    Signed-off-by: Madhan Neethiraj <[email protected]>
---
 .../RangerDefaultRowFilterPolicyItemEvaluator.java |  9 ++-
 .../apache/ranger/plugin/util/JavaScriptEdits.java | 77 ++++++++++++++++++++++
 .../ranger/plugin/util/JavaScriptEditsTest.java    | 45 +++++++++++++
 3 files changed, 130 insertions(+), 1 deletion(-)

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 d2b3e746b..759c0ff59 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,6 +25,7 @@ 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.JavaScriptEdits;
 import org.apache.ranger.plugin.util.RangerRequestExprResolver;
 
 
@@ -41,7 +42,13 @@ public class RangerDefaultRowFilterPolicyItemEvaluator 
extends RangerDefaultPoli
                RangerPolicyItemRowFilterInfo rowFilterInfo = 
getRowFilterInfo();
 
                if (rowFilterInfo != null && rowFilterInfo.getFilterExpr() != 
null) {
-                       rowFilterExpr = rowFilterInfo.getFilterExpr();
+                       String rowFilterExpr = rowFilterInfo.getFilterExpr();
+
+                       if (JavaScriptEdits.hasDoubleBrackets(rowFilterExpr)) {
+                               rowFilterExpr = 
JavaScriptEdits.replaceDoubleBrackets(rowFilterExpr);
+                       }
+
+                       this.rowFilterExpr = rowFilterExpr;
                } else {
                        rowFilterExpr = null;
                }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/JavaScriptEdits.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/JavaScriptEdits.java
new file mode 100644
index 000000000..a2dd18e4f
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/JavaScriptEdits.java
@@ -0,0 +1,77 @@
+/*
+ * 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.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class JavaScriptEdits {
+    private static final Logger LOG = 
LoggerFactory.getLogger(JavaScriptEdits.class);
+
+    private static final String  DOUBLE_BRACKET_START   = "[[";
+    private static final String  DOUBLE_BRACKET_END     = "]]";
+    private static final String  DOUBLE_BRACKET_REGEX   = 
"\\[\\[([}{\\$\"a-zA-Z0-9_.\\[\\]]+)(\\,['\\\"](.+?)['\\\"])*\\]\\]"; // regex: 
/\[\[([a-zA-Z0-9_.\[\]]+)(\,['"](.+)['"])*\]\]/g;
+    private static final Pattern DOUBLE_BRACKET_PATTERN = 
Pattern.compile(DOUBLE_BRACKET_REGEX);
+
+    public static boolean hasDoubleBrackets(String str) {
+        return StringUtils.contains(str, DOUBLE_BRACKET_START) && 
StringUtils.contains(str, DOUBLE_BRACKET_END);
+    }
+
+    /* some examples:
+    tag-based access policy:
+        original: [[TAG.value]].intersects([[USER[TAG._type]]])
+        replaced: TAG.value.split(",").intersects(USER[TAG._type].split(","))
+    Row-filter policy:
+        original: ${{[["$USER.eventType",'|']]}}.includes(eventType)
+        replaced: 
${{"$USER.eventType".split("|")}}.includes(jsonAttr.eventType)
+    */
+    public static String replaceDoubleBrackets(String str) {
+        // Besides trivial inputs, re has been tested on ${{USER.x}} and 
multiple [[]]'s
+        String ret = str;
+
+        for (Matcher m = DOUBLE_BRACKET_PATTERN.matcher(str); m.find(); ) {
+            String tokenToReplace = m.group(0);
+            String expr           = m.group(1);
+            String delimiterSpec  = m.group(2);
+            String delimiter      = m.group(3);
+
+            if (delimiter == null) {
+                delimiter = ",";
+            }
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("replaceDoubleBrackets({}): tokenToReplace={} 
expr={} delimiterSpec={} delimiter={}", str, tokenToReplace, expr, 
delimiterSpec, delimiter);
+            }
+
+            ret = ret.replace(tokenToReplace, expr + ".split(\"" + delimiter + 
"\")");
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== replaceDoubleBrackets({}): ret={}", str, ret);
+        }
+
+        return ret;
+    }
+}
+
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/util/JavaScriptEditsTest.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/util/JavaScriptEditsTest.java
new file mode 100644
index 000000000..f531290d3
--- /dev/null
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/util/JavaScriptEditsTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.assertEquals;
+
+public class JavaScriptEditsTest {
+
+       @Test
+       public void testExpressions() {
+               Map<String, String> tests = new HashMap<>();
+
+               tests.put("[[TAG.value]].intersects([[USER[TAG._type]]])", 
"TAG.value.split(\",\").intersects(USER[TAG._type].split(\",\"))");
+               
tests.put("${{[[\"$USER.eventType\",'|']]}}.includes(jsonAttr.eventType)", 
"${{\"$USER.eventType\".split(\"|\")}}.includes(jsonAttr.eventType)");
+               tests.put("TAG.value == 'email'", "TAG.value == 'email'");      
 // output same as input
+               tests.put("UGNAMES[0] == 'analyst'", "UGNAMES[0] == 
'analyst'"); // output same as input
+
+               for (Map.Entry<String, String> test : tests.entrySet()) {
+                       String input  = test.getKey();
+                       String output = test.getValue();
+
+                       assertEquals("input: " + input, output, 
JavaScriptEdits.replaceDoubleBrackets(input));
+               }
+       }
+}

Reply via email to