[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&quot;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