[prev in list] [next in list] [prev in thread] [next in thread]
List: jakarta-commons-dev
Subject: [commons-jexl] 05/07: JEXL-381: expose setting JexlEngine used by scripting; expose setting default
From: henrib () apache ! org
Date: 2022-10-31 14:25:57
Message-ID: 20221031142552.9323C440188 () gitbox2-he-fi ! apache ! org
[Download RAW message or body]
This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch JEXL-381
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
commit a42411b5c4acdf838054a0ef8b91ab0314c47242
Author: henrib <henrib@apache.org>
AuthorDate: Mon Oct 24 17:27:36 2022 +0200
JEXL-381: expose setting JexlEngine used by scripting; expose setting default \
JexlBuilder permissions;
---
.../java/org/apache/commons/jexl3/JexlBuilder.java | 40 ++++++++----
.../commons/jexl3/scripting/JexlScriptEngine.java | 72 +++++++++++++++++-----
.../jexl3/scripting/JexlScriptEngineTest.java | 41 ++++++++++++
3 files changed, 128 insertions(+), 25 deletions(-)
diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java \
b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java index 52316bf2..a183d402 \
100644
--- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
@@ -81,6 +81,21 @@ import java.nio.charset.Charset;
*
*/
public class JexlBuilder {
+ /**
+ * The set of default permissions used when creating a new builder.
+ * <p>Static but modifiable so these default permissions can be changed to a \
purposeful set.</p> + * <p>In JEXL 3.3, these are {@link \
JexlPermissions#RESTRICTED}.</p> + * <p>In JEXL 3.2, these were equivalent to \
{@link JexlPermissions#UNRESTRICTED}.</p> + */
+ private static JexlPermissions PERMISSIONS = JexlPermissions.RESTRICTED;
+
+ /**
+ * Sets the default permissions.
+ * @param permissions the permissions
+ */
+ public static void setDefaultPermissions(JexlPermissions permissions) {
+ PERMISSIONS = permissions == null? JexlPermissions.RESTRICTED : permissions;
+ }
/** The default maximum expression length to hit the expression cache. */
protected static final int CACHE_THRESHOLD = 64;
@@ -88,11 +103,11 @@ public class JexlBuilder {
/** The JexlUberspect instance. */
private JexlUberspect uberspect = null;
- /** The strategy strategy. */
+ /** The {@link JexlUberspect} resolver strategy. */
private JexlUberspect.ResolverStrategy strategy = null;
/** The set of permissions. */
- private JexlPermissions permissions = JexlPermissions.RESTRICTED;
+ private JexlPermissions permissions;
/** The sandbox. */
private JexlSandbox sandbox = null;
@@ -137,7 +152,7 @@ public class JexlBuilder {
* Default constructor.
* <p>
* As of JEXL 3.3, to reduce the security risks inherent to JEXL"s purpose, \
the builder will use a set of
- * restricted permissions as a default to create the JexlEngine instance. This \
will greatly reduce which classes + * restricted permissions as a default to \
create the {@link JexlEngine} instance. This will greatly reduce \
which classes
* and methods are visible to JEXL and usable in scripts using default implicit \
behaviors.
* </p><p>
* However, without mitigation, this change will likely break some scripts at \
runtime, especially those exposing @@ -148,16 +163,19 @@ public class JexlBuilder {
* allowed and exposed to script authors and implement those through a set of \
{@link JexlPermissions};
* those are easily created using {@link JexlPermissions#parse(String...)}.
* </p><p>
- * In the urgent case of a strict 3.2 compatiblity, the simplest and fastest \
mitigation is to use the 'unrestricted'
- * set of permissions. The builder must be explicit about it using
- * <code>new JexlBuilder().permissions({@link \
JexlPermissions#UNRESTRICTED})</code>. + * In the urgent case of a strict 3.2 \
compatibility, the simplest and fastest mitigation is to use the 'unrestricted' + \
* set of permissions. The builder must be explicit about it either by setting the \
default permissions with a + * statement like \
<code>JexlBuilder.setDefaultPermissions(JexlPermissions.UNRESTRICTED);</code> or with \
a more precise + * one like <code>new JexlBuilder().permissions({@link \
JexlPermissions#UNRESTRICTED})</code>.
* </p><p>
- * Note that an explicit call to {@link #uberspect(JexlUberspect)} will \
supersede this behavior using the
- * {@link JexlUberspect} provided instance in the {@link JexlEngine}.
+ * Note that an explicit call to {@link #uberspect(JexlUberspect)} will \
supersede any permissions related behavior + * by using the {@link JexlUberspect} \
provided as argument used as-is in the created {@link JexlEngine}.
* </p>
* @since 3.3
*/
- public JexlBuilder() {}
+ public JexlBuilder() {
+ this.permissions = PERMISSIONS;
+ }
/**
* Sets the JexlUberspect instance the engine will use.
@@ -192,7 +210,7 @@ public class JexlBuilder {
}
/**
- * Sets the JexlUberspect strategy strategy the engine will use.
+ * Sets the JexlUberspect strategy the engine will use.
* <p>This is ignored if the uberspect has been set.
*
* @param rs the strategy
@@ -203,7 +221,7 @@ public class JexlBuilder {
return this;
}
- /** @return the strategy strategy */
+ /** @return the JexlUberspect strategy */
public JexlUberspect.ResolverStrategy strategy() {
return this.strategy;
}
diff --git a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java \
b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java index \
e1845974..3611afa5 100644
--- a/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
+++ b/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
@@ -22,6 +22,8 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
@@ -39,6 +41,7 @@ import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlScript;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -63,6 +66,59 @@ import org.apache.commons.logging.LogFactory;
* @since 2.0
*/
public class JexlScriptEngine extends AbstractScriptEngine implements Compilable {
+ /**
+ * The shared engine instance.
+ * <p>A single soft-reference JEXL engine and JexlUberspect is shared by all \
instances of JexlScriptEngine.</p> + */
+ private static Reference<JexlEngine> ENGINE = null;
+
+ /**
+ * Sets the shared instance used for the script engine.
+ * <p>This should be called early enough to have an effect, ie before any
+ * {@link javax.script.ScriptEngineManager} features.</p>
+ * <p>To restore 3.2 script permeability:</p>
+ * <code>
+ * JexlScriptEngine.setInstance(new JexlBuilder()
+ * .cache(512)
+ * .logger(LogFactory.getLog(JexlScriptEngine.class))
+ * .permissions(JexlPermissions.UNRESTRICTED)
+ * .create());
+ * </code>
+ * <p>Alternatively, setting the default {@link \
JexlBuilder#setDefaultPermissions(JexlPermissions)} using + * {@link \
org.apache.commons.jexl3.introspection.JexlPermissions#UNRESTRICTED} will also \
restore JEXL 3.2 + * behavior.</p>
+ * <code>
+ * JexlBuilder.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
+ * </code>
+ * @param engine the JexlEngine instance to use
+ * @since 3.3
+ */
+ public static void setInstance(JexlEngine engine) {
+ ENGINE = new SoftReference<>(engine);
+ }
+
+ /**
+ * @return the shared JexlEngine instance, create it if necessary
+ */
+ private static JexlEngine getEngine() {
+ JexlEngine engine = ENGINE != null? ENGINE.get() : null;
+ if (engine == null) {
+ synchronized (JexlScriptEngineFactory.class) {
+ engine = ENGINE != null? ENGINE.get() : null;
+ if (engine == null) {
+ JexlBuilder builder = new JexlBuilder()
+ .strict(true)
+ .safe(false)
+ .logger(JexlScriptEngine.LOG)
+ .cache(JexlScriptEngine.CACHE_SIZE);
+ engine = builder.create();
+ ENGINE = new SoftReference<>(engine);
+ }
+ }
+ }
+ return engine;
+ }
+
/** The logger. */
static final Log LOG = LogFactory.getLog(JexlScriptEngine.class);
@@ -197,7 +253,7 @@ public class JexlScriptEngine extends AbstractScriptEngine \
implements Compilable
throw new NullPointerException("ScriptEngineFactory must not be null");
}
parentFactory = factory;
- jexlEngine = EngineSingletonHolder.DEFAULT_ENGINE;
+ jexlEngine = getEngine();
jexlObject = new JexlScriptObject();
}
@@ -307,19 +363,7 @@ public class JexlScriptEngine extends AbstractScriptEngine \
implements Compilable private FactorySingletonHolder() {}
/** The engine factory singleton instance. */
- static final JexlScriptEngineFactory DEFAULT_FACTORY = new \
JexlScriptEngineFactory();
- }
-
- /**
- * Holds singleton JexlScriptEngine (IODH).
- * <p>A single JEXL engine and JexlUberspect is shared by all instances of \
JexlScriptEngine.</p>
- */
- private static class EngineSingletonHolder {
- /** non instantiable. */
- private EngineSingletonHolder() {}
-
- /** The JEXL engine singleton instance. */
- static final JexlEngine DEFAULT_ENGINE = new \
JexlBuilder().logger(LOG).cache(CACHE_SIZE).create(); + private static final \
JexlScriptEngineFactory DEFAULT_FACTORY = new JexlScriptEngineFactory(); }
/**
diff --git a/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java \
b/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java index \
91e5d78b..e119eb65 100644
--- a/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
+++ b/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
@@ -29,8 +29,13 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
+import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
+import org.apache.commons.logging.LogFactory;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
public class JexlScriptEngineTest {
@@ -42,6 +47,16 @@ public class JexlScriptEngineTest {
"application/x-jexl2",
"application/x-jexl3");
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ JexlBuilder.setDefaultPermissions(null);
+ JexlScriptEngine.setInstance(null);
+ }
+
@Test
public void testScriptEngineFactory() throws Exception {
final JexlScriptEngineFactory factory = new JexlScriptEngineFactory();
@@ -108,6 +123,32 @@ public class JexlScriptEngineTest {
Assert.assertEquals(System.class,engine.eval("JEXL.System"));
}
+ @Test
+ public void testScriptingInstance0() throws Exception {
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ JexlScriptEngine.setInstance(new JexlBuilder()
+ .cache(512)
+ .logger(LogFactory.getLog(JexlScriptEngine.class))
+ .permissions(JexlPermissions.UNRESTRICTED)
+ .create());
+ final ScriptEngine engine = manager.getEngineByName("jexl3");
+ Long time2 = (Long) engine.eval(
+ "sys=context.class.forName(\"java.lang.System\");"
+ + "now=sys.currentTimeMillis();");
+ Assert.assertTrue(time2 <= System.currentTimeMillis());
+ }
+
+ @Test
+ public void testScriptingPermissions1() throws Exception {
+ JexlBuilder.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ final ScriptEngine engine = manager.getEngineByName("jexl3");
+ Long time2 = (Long) engine.eval(
+ "sys=context.class.forName(\"java.lang.System\");"
+ + "now=sys.currentTimeMillis();");
+ Assert.assertTrue(time2 <= System.currentTimeMillis());
+ }
+
@Test
public void testNulls() throws Exception {
final ScriptEngineManager manager = new ScriptEngineManager();
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic