You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2022/11/07 15:47:06 UTC

[commons-jexl] branch JEXL-381 updated (8760868c -> 241f9615)

This is an automated email from the ASF dual-hosted git repository.

henrib pushed a change to branch JEXL-381
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


    from 8760868c JEXL-381: added import/namespace pragma feature to enable/disable syntax; - added JexlUberspect#getClassByName that verifies permissions, use it when resolving namespaces; - updated restricted permissions set based on Dmitri feedback;
     add bf432e8f More grammar cleanup
     add 6bc2513e Merge pull request #135 from dmitri-blinov/apache-master
     new ae76290a JEXL-381: change permissions default, update tests, add javadoc;
     new 9245f2dc JEXL-381: attempt to fix cyclic permission init;
     new 5e7ed3cd JEXL-381: removed unused import;
     new fcc0d5f7 JEXL-381: removed unused import;
     new 9083d623 JEXL-381: expose setting JexlEngine used by scripting; expose setting default JexlBuilder permissions;
     new dc190a90 JEXL-381: rebased;
     new 2e62ceee JEXL-381: expose setting JexlEngine used by scripting; expose setting default JexlBuilder permissions;
     new 2b027b46 JEXL-381: added import/namespace pragma feature to enable/disable syntax; - added JexlUberspect#getClassByName that verifies permissions, use it when resolving namespaces; - updated restricted permissions set based on Dmitri feedback;
     new 241f9615 Merge remote-tracking branch 'origin/JEXL-381' into JEXL-381

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/main/java/org/apache/commons/jexl3/parser/Parser.jjt | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)


[commons-jexl] 02/09: JEXL-381: attempt to fix cyclic permission init;

Posted by he...@apache.org.
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 9245f2dc3b0150aa82ac20004cd7c897e1b9abec
Author: henrib <he...@apache.org>
AuthorDate: Fri Oct 21 20:05:02 2022 +0200

    JEXL-381: attempt to fix cyclic permission init;
---
 .../commons/jexl3/internal/introspection/PermissionsParser.java       | 3 +++
 .../java/org/apache/commons/jexl3/introspection/JexlPermissions.java  | 4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java
index 165aef3c..317030ae 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java
@@ -75,6 +75,9 @@ public class PermissionsParser {
      * @return the permissions map
      */
     public Permissions parse(String... srcs) {
+        if (srcs == null || srcs.length == 0) {
+            return Permissions.UNRESTRICTED;
+        }
         packages = new ConcurrentHashMap<>();
         wildcards = new LinkedHashSet<>();
         for(String src : srcs) {
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
index 2fca219c..5bb250cf 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
@@ -166,7 +166,7 @@ public interface JexlPermissions {
      * @since 3.3
      */
     static JexlPermissions parse(String... src) {
-        return src == null || src.length == 0? Permissions.UNRESTRICTED : new PermissionsParser().parse(src);
+        return new PermissionsParser().parse(src);
     }
 
     /**
@@ -174,7 +174,7 @@ public interface JexlPermissions {
      * <p>This enables any public class, method, constructor or field to be visible to JEXL and used in scripts.</p>
      * @since 3.3
      */
-    public static final JexlPermissions UNRESTRICTED = Permissions.UNRESTRICTED;
+    public static final JexlPermissions UNRESTRICTED = JexlPermissions.parse(null);
     /**
      * A restricted singleton.
      * <p>The RESTRICTED set is built using the following allowed packages and denied packages/classes.</p>


[commons-jexl] 04/09: JEXL-381: removed unused import;

Posted by he...@apache.org.
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 fcc0d5f7350f752af97909427e8dc47c346983de
Author: henrib <he...@apache.org>
AuthorDate: Fri Oct 21 20:10:13 2022 +0200

    JEXL-381: removed unused import;
---
 src/main/java/org/apache/commons/jexl3/internal/Engine.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
index 9d72bd8b..54630f58 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -25,7 +25,6 @@ import org.apache.commons.jexl3.JexlFeatures;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.JexlOptions;
 import org.apache.commons.jexl3.JexlScript;
-import org.apache.commons.jexl3.internal.introspection.Permissions;
 import org.apache.commons.jexl3.internal.introspection.SandboxUberspect;
 import org.apache.commons.jexl3.internal.introspection.Uberspect;
 import org.apache.commons.jexl3.introspection.JexlMethod;


[commons-jexl] 09/09: Merge remote-tracking branch 'origin/JEXL-381' into JEXL-381

Posted by he...@apache.org.
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 241f9615d5c3343266186df5d7f79787677e41fa
Merge: 2b027b46 8760868c
Author: henrib <he...@apache.org>
AuthorDate: Mon Nov 7 16:47:03 2022 +0100

    Merge remote-tracking branch 'origin/JEXL-381' into JEXL-381

 pom.xml                                            |  5 +++-
 .../java/org/apache/commons/jexl3/JexlBuilder.java | 34 +++++++++++++---------
 2 files changed, 24 insertions(+), 15 deletions(-)


[commons-jexl] 08/09: JEXL-381: added import/namespace pragma feature to enable/disable syntax; - added JexlUberspect#getClassByName that verifies permissions, use it when resolving namespaces; - updated restricted permissions set based on Dmitri feedback;

Posted by he...@apache.org.
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 2b027b4676fbd08c98f37b7014d3a158ef2bade1
Author: henrib <he...@apache.org>
AuthorDate: Mon Nov 7 14:58:17 2022 +0100

    JEXL-381: added import/namespace pragma feature to enable/disable syntax;
    - added JexlUberspect#getClassByName that verifies permissions, use it when resolving namespaces;
    - updated restricted permissions set based on Dmitri feedback;
---
 .../org/apache/commons/jexl3/JexlFeatures.java     | 85 ++++++++++++++++++----
 .../org/apache/commons/jexl3/internal/Engine.java  | 29 +++-----
 .../jexl3/internal/introspection/Introspector.java | 12 +--
 .../internal/introspection/SandboxUberspect.java   |  5 ++
 .../jexl3/introspection/JexlPermissions.java       |  6 +-
 .../commons/jexl3/introspection/JexlUberspect.java | 24 ++++--
 .../apache/commons/jexl3/parser/JexlParser.java    | 16 +++-
 .../java/org/apache/commons/jexl3/PragmaTest.java  | 33 ++++++++-
 .../internal/introspection/PermissionsTest.java    |  5 +-
 .../commons/jexl3/jexl342/ReferenceUberspect.java  |  4 +
 10 files changed, 170 insertions(+), 49 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
index 124468fb..2b692fd1 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
@@ -60,7 +60,7 @@ public final class JexlFeatures {
         "register", "reserved variable", "local variable", "assign/modify",
         "global assign/modify", "array reference", "create instance", "loop", "function",
         "method call", "set/map/array literal", "pragma", "annotation", "script", "lexical", "lexicalShade",
-        "thin-arrow", "fat-arrow"
+        "thin-arrow", "fat-arrow", "namespace pragma", "import pragma"
     };
     /** Registers feature ordinal. */
     private static final int REGISTER = 0;
@@ -98,24 +98,35 @@ public final class JexlFeatures {
     public static final int THIN_ARROW = 16;
     /** Fat-arrow lambda syntax. */
     public static final int FAT_ARROW = 17;
+    /** Namespace pragma feature ordinal. */
+    public static final int NS_PRAGMA = 18;
+    /** Import pragma feature ordinal. */
+    public static final int IMPORT_PRAGMA = 19;
+    /**
+     * The default features flag mask.
+     */
+    private static final long DEFAULT_FEATURES =
+            (1L << LOCAL_VAR)
+            | (1L << SIDE_EFFECT)
+            | (1L << SIDE_EFFECT_GLOBAL)
+            | (1L << ARRAY_REF_EXPR)
+            | (1L << NEW_INSTANCE)
+            | (1L << LOOP)
+            | (1L << LAMBDA)
+            | (1L << METHOD_CALL)
+            | (1L << STRUCTURED_LITERAL)
+            | (1L << PRAGMA)
+            | (1L << ANNOTATION)
+            | (1L << SCRIPT)
+            | (1L << THIN_ARROW)
+            | (1L << NS_PRAGMA)
+            | (1L << IMPORT_PRAGMA);
 
     /**
      * Creates an all-features-enabled instance.
      */
     public JexlFeatures() {
-        flags = (1L << LOCAL_VAR)
-                | (1L << SIDE_EFFECT)
-                | (1L << SIDE_EFFECT_GLOBAL)
-                | (1L << ARRAY_REF_EXPR)
-                | (1L << NEW_INSTANCE)
-                | (1L << LOOP)
-                | (1L << LAMBDA)
-                | (1L << METHOD_CALL)
-                | (1L << STRUCTURED_LITERAL)
-                | (1L << PRAGMA)
-                | (1L << ANNOTATION)
-                | (1L << SCRIPT)
-                | (1L << THIN_ARROW);
+        flags = DEFAULT_FEATURES;
         reservedNames = Collections.emptySet();
         nameSpaces = TEST_STR_FALSE;
     }
@@ -489,16 +500,60 @@ public final class JexlFeatures {
      */
     public JexlFeatures pragma(final boolean flag) {
         setFeature(PRAGMA, flag);
+        if (!flag) {
+            setFeature(NS_PRAGMA, false);
+            setFeature(IMPORT_PRAGMA, false);
+        }
         return this;
     }
 
     /**
-     * @return true if pragma are enabled, false otherwise
+     * @return true if namespace pragma are enabled, false otherwise
      */
     public boolean supportsPragma() {
         return getFeature(PRAGMA);
     }
 
+    /**
+     * Sets whether namespace pragma constructs are enabled.
+     * <p>
+     * When disabled, parsing a script/expression using syntactic namespace pragma constructs
+     * (#pragma jexl.namespace....) will throw a parsing exception.
+     * @param flag true to enable, false to disable
+     * @return this features instance
+     */
+    public JexlFeatures namespacePragma(final boolean flag) {
+        setFeature(NS_PRAGMA, flag);
+        return this;
+    }
+
+    /**
+     * @return true if namespace pragma are enabled, false otherwise
+     */
+    public boolean supportsNamespacePragma() {
+        return getFeature(NS_PRAGMA);
+    }
+    /**
+     * Sets whether import pragma constructs are enabled.
+     * <p>
+     * When disabled, parsing a script/expression using syntactic import pragma constructs
+     * (#pragma jexl.import....) will throw a parsing exception.
+     * @param flag true to enable, false to disable
+     * @return this features instance
+     */
+    public JexlFeatures importPragma(final boolean flag) {
+        setFeature(IMPORT_PRAGMA, flag);
+        return this;
+    }
+
+    /**
+     * @return true if import pragma are enabled, false otherwise
+     */
+    public boolean supportsImportPragma() {
+        return getFeature(IMPORT_PRAGMA);
+    }
+
+
     /**
      * Sets whether annotation constructs are enabled.
      * <p>
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
index 54630f58..2e384983 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -56,6 +56,10 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Predicate;
 
+import static org.apache.commons.jexl3.parser.JexlParser.PRAGMA_IMPORT;
+import static org.apache.commons.jexl3.parser.JexlParser.PRAGMA_JEXLNS;
+import static org.apache.commons.jexl3.parser.JexlParser.PRAGMA_OPTIONS;
+
 /**
  * A JexlEngine implementation.
  * @since 2.0
@@ -79,18 +83,6 @@ public class Engine extends JexlEngine {
         /** Non-instantiable. */
         private UberspectHolder() {}
     }
-    /**
-     * The name of the options pragma.
-     */
-    protected static final String PRAGMA_OPTIONS = "jexl.options";
-    /**
-     * The prefix of a namespace pragma.
-     */
-    protected static final String PRAGMA_JEXLNS = "jexl.namespace.";
-    /**
-     * The prefix of an import pragma.
-     */
-    protected static final String PRAGMA_IMPORT = "jexl.import";
     /**
      * The Log to which all JexlEngine messages will be logged.
      */
@@ -353,7 +345,7 @@ public class Engine extends JexlEngine {
     /**
      * Extracts the engine evaluation options from context if available, the engine
      * options otherwise.
-     * <p>If the context is a options handle and the handled options shared instance flag
+     * <p>If the context is an options handle and the handled options shared instance flag
      * is false, this method creates a copy of the options making them immutable during execution.
      * @param context the context
      * @return the options if any
@@ -457,15 +449,16 @@ public class Engine extends JexlEngine {
                     if (value instanceof String) {
                         // jexl.namespace.***
                         final String nsname = key.substring(PRAGMA_JEXLNS.length());
-                        if (nsname != null && !nsname.isEmpty()) {
+                        if (!nsname.isEmpty()) {
                             if (ns == null) {
                                 ns = new HashMap<>(functions);
                             }
                             final String nsclass = value.toString();
-                            try {
-                                ns.put(nsname, uberspect.getClassLoader().loadClass(nsclass));
-                            } catch (final ClassNotFoundException e) {
-                                ns.put(nsname, nsclass);
+                            Class<?> clazz = uberspect.getClassByName(nsclass);
+                            if (clazz == null) {
+                                logger.warn(key + ": unable to find class " + nsclass);
+                            } else {
+                                ns.put(nsname, clazz);
                             }
                         }
                     }
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
index 869c5405..761d1af2 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
@@ -62,7 +62,7 @@ public final class Introspector {
     /**
      * the logger.
      */
-    protected final Log logger;
+    private final Log logger;
     /**
      * The class loader used to solve constructors if needed.
      */
@@ -78,15 +78,15 @@ public final class Introspector {
     /**
      * Holds the method maps for the classes we know about, keyed by Class.
      */
-    private final Map<Class<?>, ClassMap> classMethodMaps = new HashMap<Class<?>, ClassMap>();
+    private final Map<Class<?>, ClassMap> classMethodMaps = new HashMap<>();
     /**
      * Holds the map of classes ctors we know about as well as unknown ones.
      */
-    private final Map<MethodKey, Constructor<?>> constructorsMap = new HashMap<MethodKey, Constructor<?>>();
+    private final Map<MethodKey, Constructor<?>> constructorsMap = new HashMap<>();
     /**
      * Holds the set of classes we have introspected.
      */
-    private final Map<String, Class<?>> constructibleClasses = new HashMap<String, Class<?>>();
+    private final Map<String, Class<?>> constructibleClasses = new HashMap<>();
 
     /**
      * Create the introspector.
@@ -116,7 +116,8 @@ public final class Introspector {
      */
     public Class<?> getClassByName(final String className) {
         try {
-            return Class.forName(className, false, loader);
+            Class<?> clazz = Class.forName(className, false, loader);
+            return permissions.allow(clazz)? clazz : null;
         } catch (final ClassNotFoundException xignore) {
             return null;
         }
@@ -279,7 +280,6 @@ public final class Introspector {
                             + cname + "."
                             + key.debugString(), xnotfound);
                 }
-                ctor = null;
             } catch (final MethodKey.AmbiguousException xambiguous) {
                 if (logger != null  && xambiguous.isSevere() &&  logger.isInfoEnabled()) {
                     logger.info("ambiguous constructor invocation: "
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
index c2a98ce5..314b8acb 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
@@ -68,6 +68,11 @@ public final class SandboxUberspect implements JexlUberspect {
         return uberspect.getVersion();
     }
 
+    @Override
+    public Class<?> getClassByName(final String className) {
+        return uberspect.getClassByName(className);
+    }
+
     @Override
     public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
         final String className;
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
index 97243680..ce9b95db 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
@@ -223,7 +223,9 @@ public interface JexlPermissions {
             "org.apache.commons.jexl3.*",
             "org.apache.commons.jexl3 { JexlBuilder {} }",
             "org.apache.commons.jexl3.internal { Engine {} }",
-            "java.lang { Runtime {} System {} ProcessBuilder {} Class {} }",
+            "java.lang { Runtime{} System{} ProcessBuilder{} Process{}" +
+                    " RuntimePermission{} SecurityManager{}" +
+                    " Thread{} ThreadGroup{} Class{} }",
             "java.lang.annotation {}",
             "java.lang.instrument {}",
             "java.lang.invoke {}",
@@ -231,7 +233,7 @@ public interface JexlPermissions {
             "java.lang.ref {}",
             "java.lang.reflect {}",
             "java.net {}",
-            "java.io { File { } }",
+            "java.io { File{} FileDescriptor{} }",
             "java.nio { Path { } Paths { } Files { } }",
             "java.rmi"
     );
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
index 08a9b02f..009e8149 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
@@ -37,7 +37,7 @@ public interface JexlUberspect {
      * Abstracts getting property setter and getter.
      * <p>
      * These are used through 'strategies' to solve properties; a strategy orders a list of resolver types,
-     * and each resolver type is tried in sequence; the first resolver that discovers a non null {s,g}etter
+     * and each resolver type is tried in sequence; the first resolver that discovers a non-null {s,g}etter
      * stops the search.
      *
      * @see JexlResolver
@@ -115,7 +115,7 @@ public interface JexlUberspect {
     /**
      * A resolver types list tailored for POJOs, favors '.' over '[]'.
      */
-    static final List<PropertyResolver> POJO = Collections.unmodifiableList(Arrays.asList(
+    List<PropertyResolver> POJO = Collections.unmodifiableList(Arrays.asList(
             JexlResolver.PROPERTY,
             JexlResolver.MAP,
             JexlResolver.LIST,
@@ -128,7 +128,7 @@ public interface JexlUberspect {
     /**
      * A resolver types list tailored for Maps, favors '[]' over '.'.
      */
-    static final List<PropertyResolver> MAP = Collections.unmodifiableList(Arrays.asList(
+    List<PropertyResolver> MAP = Collections.unmodifiableList(Arrays.asList(
             JexlResolver.MAP,
             JexlResolver.LIST,
             JexlResolver.DUCK,
@@ -165,7 +165,7 @@ public interface JexlUberspect {
      * If the operator is '[]' or if the operator is null and the object is a map, use the MAP list of resolvers;
      * Other cases use the POJO list of resolvers.
      */
-    static final ResolverStrategy JEXL_STRATEGY = (op, obj) -> {
+    ResolverStrategy JEXL_STRATEGY = (op, obj) -> {
         if (op == JexlOperator.ARRAY_GET) {
             return MAP;
         }
@@ -184,7 +184,7 @@ public interface JexlUberspect {
      * <p>If the operator is '[]' or if the object is a map, use the MAP list of resolvers.
      * Otherwise, use the POJO list of resolvers.</p>
      */
-    static final ResolverStrategy MAP_STRATEGY = (op, obj) -> {
+    ResolverStrategy MAP_STRATEGY = (op, obj) -> {
         if (op == JexlOperator.ARRAY_GET) {
             return MAP;
         }
@@ -228,6 +228,20 @@ public interface JexlUberspect {
      */
     int getVersion();
 
+    /**
+     * Seeks a class by name using this uberspect class-loader.
+     * @param className the class name
+     * @return the class instance or null if the class cannot be located by this uberspect class loader or if
+     * permissions deny access to the class
+     */
+    default Class<?> getClassByName(final String className) {
+        try {
+            return Class.forName(className, false, getClassLoader());
+        } catch (ClassNotFoundException xignore) {
+            return null;
+        }
+    }
+
     /**
      * Returns a class constructor.
      *
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
index 157ae9c2..a86119dc 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
@@ -489,10 +489,18 @@ public abstract class JexlParser extends StringParser {
         }
     }
 
+    /**
+     * The name of the options pragma.
+     */
+    public static final String PRAGMA_OPTIONS = "jexl.options";
     /**
      * The prefix of a namespace pragma.
      */
-    protected static final String PRAGMA_JEXLNS = "jexl.namespace.";
+    public static final String PRAGMA_JEXLNS = "jexl.namespace.";
+    /**
+     * The import pragma.
+     */
+    public static final String PRAGMA_IMPORT = "jexl.import";
 
     /**
      * Adds a pragma declaration.
@@ -503,12 +511,18 @@ public abstract class JexlParser extends StringParser {
         if (!getFeatures().supportsPragma()) {
             throwFeatureException(JexlFeatures.PRAGMA, getToken(0));
         }
+        if (PRAGMA_IMPORT.equals(key) && !getFeatures().supportsImportPragma()) {
+            throwFeatureException(JexlFeatures.IMPORT_PRAGMA, getToken(0));
+        }
         if (pragmas == null) {
             pragmas = new TreeMap<>();
         }
         // declaring a namespace
         Predicate<String> ns = getFeatures().namespaceTest();
         if (ns != null && key.startsWith(PRAGMA_JEXLNS)) {
+            if (!getFeatures().supportsNamespacePragma()) {
+                throwFeatureException(JexlFeatures.NS_PRAGMA, getToken(0));
+            }
             // jexl.namespace.***
             final String nsname = key.substring(PRAGMA_JEXLNS.length());
             if (!nsname.isEmpty()) {
diff --git a/src/test/java/org/apache/commons/jexl3/PragmaTest.java b/src/test/java/org/apache/commons/jexl3/PragmaTest.java
index c67fa067..4bd306aa 100644
--- a/src/test/java/org/apache/commons/jexl3/PragmaTest.java
+++ b/src/test/java/org/apache/commons/jexl3/PragmaTest.java
@@ -140,7 +140,7 @@ public class PragmaTest extends JexlTestCase {
     }
 
     @Test
-    public void testNamespacePragmaValueSet() {
+    public void testImportPragmaValueSet() {
         String src =
                 "#pragma jexl.import java.util\n"+
                 "#pragma jexl.import java.io\n"+
@@ -159,6 +159,37 @@ public class PragmaTest extends JexlTestCase {
         Assert.assertEquals(src, parsed);
     }
 
+    @Test
+    public void testImportPragmaDisabled() {
+        String src =
+                "#pragma jexl.import java.util\n"+
+                        "#pragma jexl.import java.io\n"+
+                        "#pragma jexl.import java.net\n"+
+                        "42";
+        JexlFeatures features = new JexlFeatures();
+        features.importPragma(false);
+        final JexlEngine jexl = new JexlBuilder().features(features).create();
+        try {
+            final JexlScript script = jexl.createScript(src);
+        } catch(JexlException.Parsing xparse) {
+            Assert.assertTrue(xparse.getMessage().contains("import pragma"));
+        }
+    }
+    @Test
+    public void testNamespacePragmaDisabled() {
+        JexlFeatures features = new JexlFeatures();
+        features.namespacePragma(false);
+        final JexlEngine jexl = new JexlBuilder().features(features).create();
+        try {
+            final JexlScript src = jexl.createScript(
+                    "#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
+                            + "sleeper:sleep(100);"
+                            + "42");
+            Assert.fail("should have thrown syntax exception");
+        } catch(JexlException.Parsing xparse) {
+            Assert.assertTrue(xparse.getMessage().contains("namespace pragma"));
+        }
+    }
     @Test
     @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
     public void testStaticNamespacePragma() {
diff --git a/src/test/java/org/apache/commons/jexl3/internal/introspection/PermissionsTest.java b/src/test/java/org/apache/commons/jexl3/internal/introspection/PermissionsTest.java
index 6bf36179..da0eb7a8 100644
--- a/src/test/java/org/apache/commons/jexl3/internal/introspection/PermissionsTest.java
+++ b/src/test/java/org/apache/commons/jexl3/internal/introspection/PermissionsTest.java
@@ -26,6 +26,7 @@ import org.apache.commons.jexl3.JexlTestCase;
 import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.jexl3.internal.introspection.nojexlpackage.Invisible;
 import org.apache.commons.jexl3.introspection.JexlPermissions;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -166,7 +167,7 @@ public class PermissionsTest {
 
     @Test
     public void testParsePermissions0() throws Exception {
-        String src = "java.lang { Runtime { exit(); exec(); } }";
+        String src = "java.lang { Runtime { exit(); exec(); } }\njava.net { URL {} }";
         Permissions p = (Permissions) JexlPermissions.parse(src);
         Map<String, Permissions.NoJexlPackage> nojexlmap = p.getPackages();
         Assert.assertNotNull(nojexlmap);
@@ -178,6 +179,8 @@ public class PermissionsTest {
         Method exec = getMethod(java.lang.Runtime.class,"exec");
         Assert.assertNotNull(exec);
         Assert.assertFalse(p.allow(exec));
+        JexlUberspect uber = new Uberspect(null, null, p);
+        Assert.assertNull(uber.getClassByName("java.net.URL"));
     }
 
     public static class Outer {
diff --git a/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java b/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java
index 8c44dfd5..b674334d 100644
--- a/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java
+++ b/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java
@@ -51,6 +51,10 @@ public class ReferenceUberspect implements JexlUberspect {
      * The map resolver list strategy.
      */
     private final List<PropertyResolver> mapStrategy;
+    @Override
+    public Class<?> getClassByName(final String className) {
+        return uberspect.getClassByName(className);
+    }
 
     /**
      * Constructor.


[commons-jexl] 03/09: JEXL-381: removed unused import;

Posted by he...@apache.org.
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 5e7ed3cd77203595550d044ab3828cf4bd320623
Author: henrib <he...@apache.org>
AuthorDate: Fri Oct 21 20:08:06 2022 +0200

    JEXL-381: removed unused import;
---
 .../java/org/apache/commons/jexl3/introspection/JexlPermissions.java     | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
index 5bb250cf..97243680 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.jexl3.introspection;
 
-import org.apache.commons.jexl3.internal.introspection.Permissions;
 import org.apache.commons.jexl3.internal.introspection.PermissionsParser;
 
 import java.lang.reflect.Constructor;


[commons-jexl] 01/09: JEXL-381: change permissions default, update tests, add javadoc;

Posted by he...@apache.org.
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 ae76290a020871920b71c08be128683e1741ac0e
Author: henrib <he...@apache.org>
AuthorDate: Fri Oct 21 19:33:48 2022 +0200

    JEXL-381: change permissions default, update tests, add javadoc;
---
 .../java/org/apache/commons/jexl3/JexlBuilder.java | 62 ++++++++++++++-----
 .../org/apache/commons/jexl3/internal/Engine.java  |  4 +-
 .../jexl3/internal/introspection/Introspector.java |  4 +-
 .../jexl3/internal/introspection/Permissions.java  |  4 +-
 .../jexl3/internal/introspection/Uberspect.java    |  2 +-
 .../jexl3/introspection/JexlPermissions.java       | 70 +++++++++++++++++++++-
 .../org/apache/commons/jexl3/Issues300Test.java    | 59 ++++++++++++++++++
 .../apache/commons/jexl3/PropertyAccessTest.java   |  3 +-
 .../jexl3/internal/introspection/NoJexlTest.java   |  7 +--
 .../commons/jexl3/introspection/SandboxTest.java   |  7 ++-
 .../jexl3/scripting/JexlScriptEngineTest.java      | 15 +++--
 11 files changed, 201 insertions(+), 36 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
index f0001000..52316bf2 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
@@ -31,25 +31,31 @@ import java.nio.charset.Charset;
 /**
  * Configures and builds a JexlEngine.
  *
- * <p>The builder allow fine-tuning an engine instance behavior according to various control needs.</p>
- *
- * <p>Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
+ * <p>
+ *     The builder allow fine-tuning an engine instance behavior according to various control needs.
+ *     Check <em>{@link #JexlBuilder()}</em> for permission impacts starting with <em>JEXL 3.3</em>.
+ * </p><p>
+ *     Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
  *  syntax - for instance, only expressions with no-side effects - and permissions ({@link JexlPermissions}) that control
- *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -. </p>
- *
- * <p>Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
+ *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -.
+ *  </p><p>
+ *     Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
  * common flags accessible from the builder are reflected in its options ({@link #options()}).
- * <p>The <code>silent</code> flag tells the engine what to do with the error; when true, errors are logged as
- * warning, when false, they throw {@link JexlException} exceptions.</p>
- * <p>The <code>strict</code> flag tells the engine when and if null as operand is considered an error. The <code>safe</code>
+ * </p><p>
+ *     The <code>silent</code> flag tells the engine what to do with the error; when true, errors are logged as
+ * warning, when false, they throw {@link JexlException} exceptions.
+ * </p><p>
+ *     The <code>strict</code> flag tells the engine when and if null as operand is considered an error. The <code>safe</code>
  * flog determines if safe-navigation is used. Safe-navigation allows an  evaluation shortcut and return null in expressions
- * that attempts dereferencing null, typically a method call or accessing a property.</p>
- * <p>The <code>lexical</code> and <code>lexicalShade</code> flags can be used to enforce a lexical scope for
+ * that attempts dereferencing null, typically a method call or accessing a property.
+ * </p><p>
+ *     The <code>lexical</code> and <code>lexicalShade</code> flags can be used to enforce a lexical scope for
  * variables and parameters. The <code>lexicalShade</code> can be used to further ensure no global variable can be
  * used with the same name as a local one even after it goes out of scope. The corresponding feature flags should be
- * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})</p>
- *
- * <p>The following rules apply on silent and strict flags:</p>
+ * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})
+ * </p><p>
+ *     The following rules apply on silent and strict flags:
+ * </p>
  * <ul>
  * <li>When "silent" &amp; "not-strict":
  * <p> 0 &amp; null should be indicators of "default" values so that even in an case of error,
@@ -86,7 +92,7 @@ public class JexlBuilder {
     private JexlUberspect.ResolverStrategy strategy = null;
 
     /** The set of permissions. */
-    private JexlPermissions permissions = null;
+    private JexlPermissions permissions = JexlPermissions.RESTRICTED;
 
     /** The sandbox. */
     private JexlSandbox sandbox = null;
@@ -127,6 +133,32 @@ public class JexlBuilder {
     /** The features. */
     private JexlFeatures features = null;
 
+    /**
+     * 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
+     * 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
+     * your own class instances through arguments, contexts or namespaces.
+     * The new default set of allowed packages and denied classes is described by {@link JexlPermissions#RESTRICTED}.
+     * </p><p>
+     * The recommended mitigation if your usage of JEXL is impacted is to first thoroughly review what should be
+     * 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>.
+     * </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}.
+     * </p>
+     * @since 3.3
+     */
+    public JexlBuilder() {}
+
     /**
      * Sets the JexlUberspect instance the engine will use.
      *
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
index e44802ab..9d72bd8b 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -248,7 +248,7 @@ public class Engine extends JexlEngine {
      * <p>This is lazily initialized to avoid building a default instance if there
      * is no use for it. The main reason for not using the default Uberspect instance is to
      * be able to use a (low level) introspector created with a given logger
-     * instead of the default one.</p>
+     * instead of the default one and even more so for with a different (restricted) set of permissions.</p>
      * @param logger the logger to use for the underlying Uberspect
      * @param strategy the property resolver strategy
      * @param permissions the introspection permissions
@@ -261,7 +261,7 @@ public class Engine extends JexlEngine {
             final JexlPermissions permissions) {
         if ((logger == null || logger.equals(LogFactory.getLog(JexlEngine.class)))
             && (strategy == null || strategy == JexlUberspect.JEXL_STRATEGY)
-            && permissions == null || permissions == Permissions.DEFAULT) {
+            && (permissions == null || permissions == JexlPermissions.UNRESTRICTED)) {
             return UberspectHolder.UBERSPECT;
         }
         return new Uberspect(logger, strategy, permissions);
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
index ba7a5bc5..869c5405 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
@@ -94,7 +94,7 @@ public final class Introspector {
      * @param cloader the class loader
      */
     public Introspector(final Log log, final ClassLoader cloader) {
-        this(log, cloader, Permissions.DEFAULT);
+        this(log, cloader, null);
     }
 
     /**
@@ -106,7 +106,7 @@ public final class Introspector {
     public Introspector(final Log log, final ClassLoader cloader, final JexlPermissions perms) {
         this.logger = log;
         this.loader = cloader;
-        this.permissions = perms;
+        this.permissions = perms == null? Permissions.RESTRICTED : perms;
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
index 177cf7a4..02788748 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/Permissions.java
@@ -225,9 +225,9 @@ public class Permissions implements JexlPermissions {
     }
 
     /**
-     * The default singleton.
+     * The no-restriction introspection permission singleton.
      */
-    public static final Permissions DEFAULT = new Permissions();
+    public static final Permissions UNRESTRICTED = new Permissions();
 
     /**
      * @return the packages
diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
index 8e8c3e37..1e2a01c8 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
@@ -92,7 +92,7 @@ public class Uberspect implements JexlUberspect {
     public Uberspect(final Log runtimeLogger, final JexlUberspect.ResolverStrategy sty, final JexlPermissions perms) {
         logger = runtimeLogger == null? LogFactory.getLog(JexlEngine.class) : runtimeLogger;
         strategy = sty == null? JexlUberspect.JEXL_STRATEGY : sty;
-        permissions = perms == null? Permissions.DEFAULT : perms;
+        permissions = perms == null? Permissions.RESTRICTED : perms;
         ref = new SoftReference<Introspector>(null);
         loader = new SoftReference<ClassLoader>(getClass().getClassLoader());
         operatorMap = new ConcurrentHashMap<Class<? extends JexlArithmetic>, Set<JexlOperator>>();
diff --git a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
index f0cad14d..2fca219c 100644
--- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
+++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java
@@ -46,6 +46,7 @@ import java.lang.reflect.Method;
  * @since 3.3
  */
 public interface JexlPermissions {
+
     /**
      * Checks whether a package allows JEXL introspection.
      * <p>If the package disallows JEXL introspection, none of its classes or interfaces are visible
@@ -165,7 +166,74 @@ public interface JexlPermissions {
      * @since 3.3
      */
     static JexlPermissions parse(String... src) {
-        return src == null || src.length == 0? Permissions.DEFAULT : new PermissionsParser().parse(src);
+        return src == null || src.length == 0? Permissions.UNRESTRICTED : new PermissionsParser().parse(src);
     }
 
+    /**
+     * The unrestricted permissions.
+     * <p>This enables any public class, method, constructor or field to be visible to JEXL and used in scripts.</p>
+     * @since 3.3
+     */
+    public static final JexlPermissions UNRESTRICTED = Permissions.UNRESTRICTED;
+    /**
+     * A restricted singleton.
+     * <p>The RESTRICTED set is built using the following allowed packages and denied packages/classes.</p>
+     * <p>Of particular importance are the restrictions on the {@link System},
+     * {@link Runtime}, {@link ProcessBuilder}, {@link Class} and those on {@link java.net}, {@link java.net},
+     * {@link java.io} and {@link java.lang.reflect} that should provide a decent level of isolation between the scripts
+     * and its host.
+     * </p>
+     * <p>
+     * As a simple guide, any line that ends with &quot;.*&quot; is allowing a package, any other is
+     * denying a package, class or method.
+     * </p>
+     * <ul>
+     * <li>java.nio.*</li>
+     * <li>java.io.*</li>
+     * <li>java.lang.*</li>
+     * <li>java.math.*</li>
+     * <li>java.text.*</li>
+     * <li>java.util.*</li>
+     * <li>org.w3c.dom.*</li>
+     * <li>org.apache.commons.jexl3.*</li>
+     *
+     * <li>org.apache.commons.jexl3 { JexlBuilder {} }</li>
+     * <li>org.apache.commons.jexl3.internal { Engine {} }</li>
+     * <li>java.lang { Runtime {} System {} ProcessBuilder {} Class {} }</li>
+     * <li>java.lang.annotation {}</li>
+     * <li>java.lang.instrument {}</li>
+     * <li>java.lang.invoke {}</li>
+     * <li>java.lang.management {}</li>
+     * <li>java.lang.ref {}</li>
+     * <li>java.lang.reflect {}</li>
+     * <li>java.net {}</li>
+     * <li>java.io { File { } }</li>
+     * <li>java.nio { Path { } Paths { } Files { } }</li>
+     * <li>java.rmi {}</li>
+     * </ul>
+     */
+    public static final JexlPermissions RESTRICTED = JexlPermissions.parse(
+            "# Restricted Uberspect Permissions",
+            "java.nio.*",
+            "java.io.*",
+            "java.lang.*",
+            "java.math.*",
+            "java.text.*",
+            "java.util.*",
+            "org.w3c.dom.*",
+            "org.apache.commons.jexl3.*",
+            "org.apache.commons.jexl3 { JexlBuilder {} }",
+            "org.apache.commons.jexl3.internal { Engine {} }",
+            "java.lang { Runtime {} System {} ProcessBuilder {} Class {} }",
+            "java.lang.annotation {}",
+            "java.lang.instrument {}",
+            "java.lang.invoke {}",
+            "java.lang.management {}",
+            "java.lang.ref {}",
+            "java.lang.reflect {}",
+            "java.net {}",
+            "java.io { File { } }",
+            "java.nio { Path { } Paths { } Files { } }",
+            "java.rmi"
+    );
 }
diff --git a/src/test/java/org/apache/commons/jexl3/Issues300Test.java b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
index eec25e90..78a799e7 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues300Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
@@ -31,6 +31,8 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.junit.Assert.assertEquals;
 
@@ -951,4 +953,61 @@ public class Issues300Test {
         Assert.assertEquals("'\\b\\t\\f'", parsed);
     }
 
+    /**
+     * Mock driver.
+     */
+    public static class Driver0930 {
+        private String name;
+        Driver0930(String n) {
+            name = n;
+        }
+        public String getAttributeName() {
+            return name;
+        }
+    }
+
+    public static class Context0930 extends MapContext {
+        /**
+         * This allows using a JEXL lmabda as a filter.
+         * @param stream the stream
+         * @param filter the lambda to use as filter
+         * @return the filtered stream
+         */
+        public Stream<?> filter(Stream<?> stream, JexlScript filter) {
+            return stream.filter(x -> Boolean.TRUE.equals(filter.execute(this, x)));
+        }
+    }
+
+    @Test
+    public void testStackOvflw20220930() {
+        // fill some drivers in a list
+        List<Driver0930> values = new ArrayList<>();
+        for(int i = 0; i < 8; ++i) {
+            values.add(new Driver0930("drvr" + Integer.toOctalString(i)));
+        }
+        for(int i = 0; i < 4; ++i) {
+            values.add(new Driver0930("favorite" + Integer.toOctalString(i)));
+        }
+        // Use a context that can filter and that exposes Collectors
+        JexlEngine jexl = new JexlBuilder().safe(false).create();
+        JexlContext context = new Context0930();
+        context.set("values", values);
+        context.set("Collectors", Collectors.class);
+        // The script with a JEXL 3.2 (lambda function) and 3.3 syntax (lambda expression)
+        String src32 = "values.stream().filter((driver) ->{ driver.attributeName =^ 'favorite' }).collect(Collectors.toList())";
+        String src33 = "values.stream().filter(driver -> driver.attributeName =^ 'favorite').collect(Collectors.toList())";
+        for(String src : Arrays.asList(src32, src33)) {
+            JexlExpression s = jexl.createExpression(src);
+            Assert.assertNotNull(s);
+
+            Object r = s.evaluate(context);
+            Assert.assertNotNull(r);
+            // got a filtered list of 4 drivers whose attribute name starts with 'favorite'
+            List<Driver0930> l = (List<Driver0930>) r;
+            Assert.assertEquals(4, l.size());
+            for (Driver0930 d : l) {
+                Assert.assertTrue(d.getAttributeName().startsWith("favorite"));
+            }
+        }
+    }
 }
diff --git a/src/test/java/org/apache/commons/jexl3/PropertyAccessTest.java b/src/test/java/org/apache/commons/jexl3/PropertyAccessTest.java
index 7883c0a6..b250fc36 100644
--- a/src/test/java/org/apache/commons/jexl3/PropertyAccessTest.java
+++ b/src/test/java/org/apache/commons/jexl3/PropertyAccessTest.java
@@ -23,6 +23,7 @@ import org.apache.commons.jexl3.internal.Debugger;
 import org.apache.commons.jexl3.internal.introspection.IndexedType;
 import org.apache.commons.jexl3.internal.introspection.Permissions;
 import org.apache.commons.jexl3.internal.introspection.Uberspect;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
 import org.apache.commons.jexl3.junit.Asserter;
 import org.apache.commons.logging.LogFactory;
@@ -384,7 +385,7 @@ public class PropertyAccessTest extends JexlTestCase {
         x.put(2, "123456789");
         ctx.set("x", x);
         final JexlEngine engine = new JexlBuilder()
-                .uberspect(new Uberspect(null, null, null))
+                .uberspect(new Uberspect(null, null, JexlPermissions.UNRESTRICTED))
                 .strict(true).silent(false).create();
         String stmt = "x.2.class.name";
         JexlScript script = engine.createScript(stmt);
diff --git a/src/test/java/org/apache/commons/jexl3/internal/introspection/NoJexlTest.java b/src/test/java/org/apache/commons/jexl3/internal/introspection/NoJexlTest.java
index acfb87c5..46c29318 100644
--- a/src/test/java/org/apache/commons/jexl3/internal/introspection/NoJexlTest.java
+++ b/src/test/java/org/apache/commons/jexl3/internal/introspection/NoJexlTest.java
@@ -17,17 +17,12 @@
 package org.apache.commons.jexl3.internal.introspection;
 
 import org.apache.commons.jexl3.annotations.NoJexl;
-import org.apache.commons.jexl3.introspection.JexlPermissions;
 import org.junit.Assert;
 import org.junit.Test;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * Checks the CacheMap.MethodKey implementation
@@ -88,7 +83,7 @@ public class NoJexlTest {
 
     @Test
     public void testNoJexlPermissions() throws Exception {
-        Permissions p = Permissions.DEFAULT;
+        Permissions p = Permissions.UNRESTRICTED;
         Assert.assertFalse(p.allow((Field) null));
         Assert.assertFalse(p.allow((Package) null));
         Assert.assertFalse(p.allow((Method) null));
diff --git a/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java b/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java
index 26342818..0a3fda12 100644
--- a/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java
+++ b/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java
@@ -349,7 +349,12 @@ public class SandboxTest extends JexlTestCase {
         // can not create a new file
         sandbox.block(java.io.File.class.getName()).execute("");
 
-        final JexlEngine sjexl = new JexlBuilder().sandbox(sandbox).safe(false).strict(true).create();
+        final JexlEngine sjexl = new JexlBuilder()
+                .permissions(JexlPermissions.UNRESTRICTED)
+                .sandbox(sandbox)
+                .safe(false)
+                .strict(true)
+                .create();
 
         String expr;
         JexlScript script;
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 024da76f..91e5d78b 100644
--- a/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
+++ b/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.java
@@ -29,6 +29,7 @@ import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
 
+import org.apache.commons.jexl3.JexlException;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -83,12 +84,16 @@ public class JexlScriptEngineTest {
         final Integer initialValue = 123;
         Assert.assertEquals(initialValue,engine.eval("123"));
         Assert.assertEquals(initialValue,engine.eval("0;123"));// multiple statements
-        final long time1 = System.currentTimeMillis();
-        final Long time2 = (Long) engine.eval(
-             "sys=context.class.forName(\"java.lang.System\");"
-            +"now=sys.currentTimeMillis();"
+        try {
+            final Long time2 = (Long) engine.eval(
+                    "sys=context.class.forName(\"java.lang.System\");"
+                            + "now=sys.currentTimeMillis();"
             );
-        Assert.assertTrue("Must take some time to process this",time1 <= time2);
+            Assert.fail("default engine no longer accesses System classes");
+        } catch(ScriptException xscript) {
+            JexlException.Method xjexl = (JexlException.Method) xscript.getCause();
+            Assert.assertEquals("forName", xjexl.getMethod());
+        }
         engine.put("value", initialValue);
         Assert.assertEquals(initialValue,engine.get("value"));
         final Integer newValue = 124;


[commons-jexl] 05/09: JEXL-381: expose setting JexlEngine used by scripting; expose setting default JexlBuilder permissions;

Posted by he...@apache.org.
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 9083d623de349fd72b308cf4c70a28a4d0721814
Author: henrib <he...@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();


[commons-jexl] 06/09: JEXL-381: rebased;

Posted by he...@apache.org.
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 dc190a909b465c6838003db227524c3bd5f83e3f
Author: henrib <he...@apache.org>
AuthorDate: Fri Oct 21 19:33:48 2022 +0200

    JEXL-381: rebased;
---
 .../java/org/apache/commons/jexl3/JexlBuilder.java | 38 +++++++++-------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
index a183d402..00330c59 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
@@ -31,31 +31,25 @@ import java.nio.charset.Charset;
 /**
  * Configures and builds a JexlEngine.
  *
- * <p>
- *     The builder allow fine-tuning an engine instance behavior according to various control needs.
- *     Check <em>{@link #JexlBuilder()}</em> for permission impacts starting with <em>JEXL 3.3</em>.
- * </p><p>
- *     Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
+ * <p>The builder allow fine-tuning an engine instance behavior according to various control needs.</p>
+ *
+ * <p>Broad configurations elements are controlled through the features ({@link JexlFeatures}) that can restrict JEXL
  *  syntax - for instance, only expressions with no-side effects - and permissions ({@link JexlPermissions}) that control
- *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -.
- *  </p><p>
- *     Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
+ *  the visible set of objects - for instance, avoiding access to any object in java.rmi.* -. </p>
+ *
+ * <p>Fine error control and runtime-overridable behaviors are implemented through options ({@link JexlOptions}). Most
  * common flags accessible from the builder are reflected in its options ({@link #options()}).
- * </p><p>
- *     The <code>silent</code> flag tells the engine what to do with the error; when true, errors are logged as
- * warning, when false, they throw {@link JexlException} exceptions.
- * </p><p>
- *     The <code>strict</code> flag tells the engine when and if null as operand is considered an error. The <code>safe</code>
+ * <p>The <code>silent</code> flag tells the engine what to do with the error; when true, errors are logged as
+ * warning, when false, they throw {@link JexlException} exceptions.</p>
+ * <p>The <code>strict</code> flag tells the engine when and if null as operand is considered an error. The <code>safe</code>
  * flog determines if safe-navigation is used. Safe-navigation allows an  evaluation shortcut and return null in expressions
- * that attempts dereferencing null, typically a method call or accessing a property.
- * </p><p>
- *     The <code>lexical</code> and <code>lexicalShade</code> flags can be used to enforce a lexical scope for
+ * that attempts dereferencing null, typically a method call or accessing a property.</p>
+ * <p>The <code>lexical</code> and <code>lexicalShade</code> flags can be used to enforce a lexical scope for
  * variables and parameters. The <code>lexicalShade</code> can be used to further ensure no global variable can be
  * used with the same name as a local one even after it goes out of scope. The corresponding feature flags should be
- * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})
- * </p><p>
- *     The following rules apply on silent and strict flags:
- * </p>
+ * preferred since they will detect violations at parsing time. (see {@link JexlFeatures})</p>
+ *
+ * <p>The following rules apply on silent and strict flags:</p>
  * <ul>
  * <li>When "silent" &amp; "not-strict":
  * <p> 0 &amp; null should be indicators of "default" values so that even in an case of error,
@@ -210,7 +204,7 @@ public class JexlBuilder {
     }
 
     /**
-     * Sets the JexlUberspect strategy the engine will use.
+     * Sets the JexlUberspect strategy strategy the engine will use.
      * <p>This is ignored if the uberspect has been set.
      *
      * @param rs the strategy
@@ -221,7 +215,7 @@ public class JexlBuilder {
         return this;
     }
 
-    /** @return the JexlUberspect strategy */
+    /** @return the strategy strategy */
     public JexlUberspect.ResolverStrategy strategy() {
         return this.strategy;
     }


[commons-jexl] 07/09: JEXL-381: expose setting JexlEngine used by scripting; expose setting default JexlBuilder permissions;

Posted by he...@apache.org.
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 2e62ceee3dfe51657ed082d2744240876ffee86a
Author: henrib <he...@apache.org>
AuthorDate: Mon Oct 24 17:27:36 2022 +0200

    JEXL-381: expose setting JexlEngine used by scripting; expose setting default JexlBuilder permissions;
---
 src/main/java/org/apache/commons/jexl3/JexlBuilder.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
index 00330c59..b4ac72c5 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
@@ -204,7 +204,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
@@ -215,7 +215,7 @@ public class JexlBuilder {
         return this;
     }
 
-    /** @return the strategy strategy */
+    /** @return the JexlUberspect strategy */
     public JexlUberspect.ResolverStrategy strategy() {
         return this.strategy;
     }