This is an automated email from the ASF dual-hosted git repository.
vyommani pushed a commit to branch ranger-2.10
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/ranger-2.10 by this push:
new c03beac49 RANGER-5818: Use the common hardened script engine for
nestedstructure row-filter evaluation (#1282)
c03beac49 is described below
commit c03beac49b6a3b907581d495fa677bdbdc260e1a
Author: Vyom Mani Tiwari <[email protected]>
AuthorDate: Mon Oct 5 15:22:52 2026 +0530
RANGER-5818: Use the common hardened script engine for nestedstructure
row-filter evaluation (#1282)
---
.../policyengine/RangerRequestScriptEvaluator.java | 3 +-
.../ranger/plugin/util/ScriptEngineUtil.java | 6 ++++
.../authorizer/RecordFilterJavaScript.java | 34 +++++++++-------------
.../authorizer/TestRecordFilterJavaScript.java | 11 ++++---
4 files changed, 29 insertions(+), 25 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 437b89751..7dc7fc30e 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
@@ -32,6 +32,7 @@
import org.apache.ranger.plugin.util.RangerPerfTracer;
import org.apache.ranger.plugin.util.RangerTimeRangeChecker;
import org.apache.ranger.plugin.util.RangerUserStore;
+import org.apache.ranger.plugin.util.ScriptEngineUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -160,7 +161,7 @@ public final class RangerRequestScriptEvaluator {
private static final String DEFAULT_RANGER_TAG_ATTRIBUTE_DATE_FORMAT
= "yyyy/MM/dd";
private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT_NAME
= "ATLAS_DATE_FORMAT";
private static final String DEFAULT_ATLAS_TAG_ATTRIBUTE_DATE_FORMAT
= "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
- private static final String SCRIPT_SAFE_PREEXEC
=
"Object.defineProperty(this,'engine',{value:null,writable:false});Object.defineProperty(this,'context',{value:null,writable:false});Object.defineProperty(this,'__noSuchProperty__',{value:null,writable:false});Object.defineProperty(this,'loadWithNewGlobal',{value:null,writable:false});exit=null;quit=null;";
+ private static final String SCRIPT_SAFE_PREEXEC
= ScriptEngineUtil.SCRIPT_SAFE_PREEXEC;
private static final String SCRIPT_PREEXEC
= SCRIPT_VAR__CTX + "=JSON.parse(" + SCRIPT_VAR__CTX_JSON + ");
J=JSON.stringify;" +
SCRIPT_VAR_REQ + "=" + SCRIPT_VAR__CTX + "." +
SCRIPT_FIELD_REQUEST + ";" +
SCRIPT_VAR_RES + "=" + SCRIPT_VAR_REQ + "." +
SCRIPT_FIELD_RESOURCE + ";" +
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 1d0194e34..cbafb5392 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
@@ -31,6 +31,12 @@
public class ScriptEngineUtil {
private static final Logger LOG =
LoggerFactory.getLogger(RangerScriptConditionEvaluator.class);
+ /**
+ * Evaluated before a policy-condition or row-filter script, on the same
bindings as that script.
+ * Supplements the engine from {@link NashornScriptEngineCreator} or
{@link GraalScriptEngineCreator}.
+ */
+ public static final String SCRIPT_SAFE_PREEXEC =
"Object.defineProperty(this,'engine',{value:null,writable:false});Object.defineProperty(this,'context',{value:null,writable:false});Object.defineProperty(this,'__noSuchProperty__',{value:null,writable:false});Object.defineProperty(this,'loadWithNewGlobal',{value:null,writable:false});exit=null;quit=null;";
+
private static final String SCRIPT_ENGINE_CREATOR_NASHHORN =
"org.apache.ranger.plugin.util.NashornScriptEngineCreator";
private static final String SCRIPT_ENGINE_CREATOR_GRAAL =
"org.apache.ranger.plugin.util.GraalScriptEngineCreator";
private static final String SCRIPT_ENGINE_CREATOR_JS =
"org.apache.ranger.plugin.util.JavaScriptEngineCreator";
diff --git
a/plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
b/plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
index 77767767c..926e8a4ac 100644
---
a/plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
+++
b/plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
@@ -20,8 +20,8 @@
package org.apache.ranger.authorization.nestedstructure.authorizer;
-import jdk.nashorn.api.scripting.ClassFilter;
-import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+import org.apache.ranger.plugin.util.NashornScriptEngineCreator;
+import org.apache.ranger.plugin.util.ScriptEngineUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,7 +29,8 @@
import javax.script.ScriptEngine;
/**
- * Executes an injected javascript command to determine if the user has access
to the selected record
+ * Executes a row-filter expression to determine if the user has access to the
selected record.
+ * The engine is created by {@link NashornScriptEngineCreator}, the same
configuration policy-condition scripts use.
*/
public class RecordFilterJavaScript {
private static final Logger logger =
LoggerFactory.getLogger(RecordFilterJavaScript.class);
@@ -46,31 +47,21 @@ public class RecordFilterJavaScript {
"&& isNaN(x) && isNaN(y)); } while (k < len) { if
(sameValueZero(o[k], valueToFind)) { return true; } k++; }" +
" return false; } }); }";
-
/**
- * This class filter prevents javascript from importing, using or
reflecting any java classes
- * Helps keep javascript clean of injections. It also contains other
checks to ensure that injected
- * javascript is reasonably safe.
+ * Checks applied before evaluation, in addition to the engine
configuration.
*/
- static class SecurityFilter implements ClassFilter {
- @Override
- public boolean exposeToScripts(String s) {
- return false;
- }
-
+ static class SecurityFilter {
/**
- *
- * @param filterExpr the javascript to check if it contains
potentially harmful commands
+ * @param filterExpr the javascript to check if it contains
potentially harmful commands
* @return if this script is likely bad
*/
- boolean containsMalware(String filterExpr){
+ boolean containsMalware(String filterExpr) {
//this.engine is the javascript notation for getting access to
runtime that is executing the script
//more checks can be added here
return filterExpr.contains("this.engine");
}
}
-
public static boolean filterRow(String user, String filterExpr, String
jsonString) {
SecurityFilter securityFilter = new SecurityFilter();
@@ -78,15 +69,18 @@ public static boolean filterRow(String user, String
filterExpr, String jsonStrin
throw new MaskingException("cannot process filter expression due
to security concern \"this.engine\": " + filterExpr);
}
- NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
- ScriptEngine engine =
factory.getScriptEngine(securityFilter);
+ ScriptEngine engine = new
NashornScriptEngineCreator().getScriptEngine(null);
+
+ if (engine == null) {
+ throw new MaskingException("unable to evaluate filter expression:
script engine is not available");
+ }
if (logger.isDebugEnabled()) {
logger.debug("filterExpr: " + filterExpr);
}
// convert the given JSON string to JavaScript object, which the
filterExpr expects, and then exec the filterExpr
- String script = " jsonAttr = JSON.parse(jsonString); " +
NASHORN_POLYFILL_ARRAY_PROTOTYPE_INCLUDES + " " + filterExpr;
+ String script = ScriptEngineUtil.SCRIPT_SAFE_PREEXEC + " jsonAttr =
JSON.parse(jsonString); " + NASHORN_POLYFILL_ARRAY_PROTOTYPE_INCLUDES + " " +
filterExpr;
try {
Bindings bindings = engine.createBindings();
diff --git
a/plugin-nestedstructure/src/test/java/org/apache/ranger/authorization/nestedstructure/authorizer/TestRecordFilterJavaScript.java
b/plugin-nestedstructure/src/test/java/org/apache/ranger/authorization/nestedstructure/authorizer/TestRecordFilterJavaScript.java
index 9cb161b8d..60d0b3f16 100644
---
a/plugin-nestedstructure/src/test/java/org/apache/ranger/authorization/nestedstructure/authorizer/TestRecordFilterJavaScript.java
+++
b/plugin-nestedstructure/src/test/java/org/apache/ranger/authorization/nestedstructure/authorizer/TestRecordFilterJavaScript.java
@@ -41,12 +41,15 @@ public void testAccessJava() {
try {
RecordFilterJavaScript.filterRow("user", "bufferedWriter = new
java.io.BufferedWriter(new java.io.FileWriter('omg.txt'));\n" +
" bufferedWriter.write(\"Writing line one to
file\"); bufferedWriter.close;", TestJsonManipulator.bigTester);
-
+ Assert.fail("Java access from a row-filter expression must fail");
} catch (MaskingException e) {
- Assert.assertTrue(e.getCause() instanceof RuntimeException);
- Assert.assertTrue(e.getCause().getCause() instanceof
ClassNotFoundException);
+ Assert.assertFalse(Files.exists(Paths.get("omg.txt")));
}
- Assert.assertFalse(Files.exists(Paths.get("omg.txt")));
+ }
+
+ @Test
+ public void testEngineAndContextAreCleared() {
+ Assert.assertTrue(RecordFilterJavaScript.filterRow("user", "engine ===
null && context === null", TestJsonManipulator.bigTester));
}
@AfterTest