This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push:
new 5d358a1a JEXL-451, JEXL-450: added specific tests; - fixed a few nits
in changes, release notes; - deprecated unused methods;
5d358a1a is described below
commit 5d358a1afd26f238a03ea8bdcf6c7e754ab68a26
Author: Henrib <[email protected]>
AuthorDate: Wed Dec 3 17:45:29 2025 +0100
JEXL-451, JEXL-450: added specific tests;
- fixed a few nits in changes, release notes;
- deprecated unused methods;
---
RELEASE-NOTES.txt | 56 +--------
src/changes/changes.xml | 28 +++--
.../org/apache/commons/jexl3/internal/Engine.java | 10 +-
.../apache/commons/jexl3/internal/Engine32.java | 2 +
src/site/xdoc/relnotes35.xml | 2 +-
.../org/apache/commons/jexl3/Issues400Test.java | 137 ++++++++++++++++++---
6 files changed, 152 insertions(+), 83 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index df709786..ad417f70 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -1,61 +1,7 @@
-Apache Commons JEXL 3.6.0 Release Notes
----------------------------------------
-
-The Apache Commons JEXL team is pleased to announce the release of Apache
Commons JEXL 3.6.0.
-
-Introduction
-------------
-
-Apache Commons JEXL is a library that facilitates the implementation of
scripting features in
- applications and frameworks written in Java.
-
-This is a feature and maintenance release. Java 8 or later is required.
-
-New features
-------------
-
-o JEXL-440: Switch statement & expressions.
-
-Fixed Bugs
-----------
-
-o JEXL-448: Engines caching misses local variables handling and global
eviction capability.
-o JEXL-447: Regression in script-defined functions. Thanks to William Price.
-o JEXL-446: ClassTool module inspection is too strict. Thanks to William
Price.
-o JEXL-442: Local variables are not resolved in interpolation string
expression. Thanks to Xu Pengcheng.
-o JEXL-441: Tokenization error if "\n" in template expression. Thanks to Xu
Pengcheng.
-o JEXL-439: When using reference capture, incorrect scoping when local
variable redefines a captured symbol. Thanks to Xu Pengcheng.
-o JEXL-437: Semicolons not actually optional between function calls on
separate lines. Thanks to William Price.
-o
org.apache.commons.jexl3.internal.introspection.AbstractExecutor.initMarker(Class,
String, Class...) throws IllegalArgumentException instead of Exception. Thanks
to Gary Gregory.
-o Reuse BigInteger constants instead of creating new instances in
JexlArithmetic.toBigInteger(Object). Thanks to Gary Gregory.
-
-Changes
--------
-
-o Bump org.apache.commons:commons-parent from 81 to 91 #344, #368,
#372. Thanks to Gary Gregory, Dependabot.
-o Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.19.0 #355.
Thanks to Gary Gregory, Dependabot.
-o Bump com.google.code.gson:gson from 2.13.1 to 2.13.2 #371. Thanks
to Gary Gregory, Dependabot.
-
-
-Historical list of changes:
https://commons.apache.org/proper/commons-jexl/changes.html
-
-For complete information on Apache Commons JEXL, including instructions on how
to submit bug reports,
-patches, or suggestions for improvement, see the Apache Commons JEXL website:
-
-https://commons.apache.org/proper/commons-jexl/
-
-Download page: https://commons.apache.org/proper/commons-jexl/download_jexl.cgi
-
-Have fun!
--Apache Commons Team
-
-------------------------------------------------------------------------------
-
-
Apache Commons JEXL
- Version 3.5.0
+ Version 3.6.0
Release Notes
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d4a82f91..1c8acf92 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -27,14 +27,26 @@
<author email="[email protected]">Commons Developers</author>
</properties>
<body>
- <release version="3.6.1" date="YYYY-MM-DD" description="This is a
feature and maintenance release. Java 8 or later is required.">
- <!-- FIX -->
- <action dev="henrib" type="fix" issue="JEXL-449" due-to="William
Price">Inconsistency on nature of curly-bracket syntactic elements regarding
annotations.</action>
- <action dev="henrib" type="fix" issue="JEXL-451" due-to="Xu
Pengcheng, Henri Biestro">Restore JexlSandbox permission capabilities on
Object.class.</action>
- <!-- ADD -->
- <!-- UPDATE -->
- <action type="update" dev="ggregory" due-to="Gary Gregory,
Dependabot">Bump org.apache.commons:commons-parent from 91 to 93 #391,
#396.</action>
- <action type="update" dev="ggregory" due-to="Gary Gregory">Bump
org.apache.commons:commons-lang3 from 3.17.0 to 3.20.0.</action>
+ <release version="3.6.1" date="YYYY-MM-DD"
+ description="This is a feature and maintenance release. Java
8 or later is required.">
+ <!-- FIX -->
+ <action dev="henrib" type="fix" issue="JEXL-449" due-to="William
Price">Inconsistency on nature of
+ curly-bracket syntactic elements regarding annotations.
+ </action>
+ <action dev="henrib" type="fix" issue="JEXL-450">Disable
instantiation of internal classes in RESTRICTED
+ mode.
+ </action>
+ <action dev="henrib" type="fix" issue="JEXL-451" due-to="Xu
Pengcheng, Henri Biestro">Restore JexlSandbox
+ permission capabilities on Object.class.
+ </action>
+ <!-- ADD -->
+ <!-- UPDATE -->
+ <action type="update" dev="ggregory" due-to="Gary Gregory,
Dependabot">Bump
+ org.apache.commons:commons-parent from 91 to 93 #391, #396.
+ </action>
+ <action type="update" dev="ggregory" due-to="Gary Gregory">Bump
org.apache.commons:commons-lang3 from 3.17.0
+ to 3.20.0.
+ </action>
</release>
<release version="3.6.0" date="2025-11-10"
description="This is a feature and maintenance release. Java
8 or later is required.">
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 c494aba0..5c8126a1 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -337,6 +337,9 @@ public class Engine extends JexlEngine implements
JexlUberspect.ConstantResolver
final JexlUberspect uber = conf.uberspect() == null
? getUberspect(conf.logger(), conf.strategy(),
conf.permissions())
: conf.uberspect();
+ if (uber == null) {
+ throw new IllegalArgumentException("uberspect cannot be null");
+ }
final ClassLoader loader = conf.loader();
if (loader != null) {
uber.setClassLoader(loader);
@@ -370,9 +373,6 @@ public class Engine extends JexlEngine implements
JexlUberspect.ConstantResolver
this.metaCache = new MetaCache(factory == null ? SoftCache::new :
factory);
this.cache = metaCache.createCache(conf.cache());
this.cacheThreshold = conf.cacheThreshold();
- if (uberspect == null) {
- throw new IllegalArgumentException("uberspect cannot be null");
- }
this.parserFactory = conf.parserFactory() == null ?
() -> new Parser(new StringProvider(";"))
: conf.parserFactory();
@@ -550,7 +550,9 @@ public class Engine extends JexlEngine implements
JexlUberspect.ConstantResolver
* @param script the script
* @return the local variables array which may be empty (but not null) if
no local variables were defined
* @since 3.0
+ * @deprecated 3.6.1
*/
+ @Deprecated()
protected String[] getLocalVariables(final JexlScript script) {
return script.getLocalVariables();
}
@@ -569,7 +571,9 @@ public class Engine extends JexlEngine implements
JexlUberspect.ConstantResolver
* @param script the script
* @return the parameters which may be empty (but not null) if no
parameters were defined
* @since 3.0
+ * @deprecated 3.6.1
*/
+ @Deprecated
protected String[] getParameters(final JexlScript script) {
return script.getParameters();
}
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine32.java
b/src/main/java/org/apache/commons/jexl3/internal/Engine32.java
index eb403c44..b12b1b9d 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine32.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine32.java
@@ -31,7 +31,9 @@ import org.apache.commons.jexl3.parser.JexlNode;
/**
* An Engine that behaves like JEXL 3.2, bugs included.
+ * @deprecated 3.6.1, use Engine with JexlOptions instead.
*/
+@Deprecated
public class Engine32 extends Engine {
/**
* Static delegation of getVariable.
diff --git a/src/site/xdoc/relnotes35.xml b/src/site/xdoc/relnotes35.xml
index 75c683a0..5f646f83 100644
--- a/src/site/xdoc/relnotes35.xml
+++ b/src/site/xdoc/relnotes35.xml
@@ -18,7 +18,7 @@
<document>
<properties>
- <title>Apache Commons JEXL 3.5 Release Notes</title>
+ <title>Apache Commons JEXL 3.6 Release Notes</title>
</properties>
<body>
diff --git a/src/test/java/org/apache/commons/jexl3/Issues400Test.java
b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
index 7a494a62..1ec15961 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues400Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
@@ -42,8 +42,11 @@ import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.jexl3.internal.Debugger;
+import org.apache.commons.jexl3.internal.Engine32;
import org.apache.commons.jexl3.internal.Scope;
+import org.apache.commons.jexl3.internal.TemplateEngine;
import org.apache.commons.jexl3.introspection.JexlPermissions;
+import org.apache.commons.jexl3.introspection.JexlSandbox;
import org.apache.commons.jexl3.parser.ASTJexlScript;
import org.apache.commons.jexl3.parser.JexlScriptParser;
import org.apache.commons.jexl3.parser.Parser;
@@ -805,7 +808,8 @@ public class Issues400Test {
final JexlScript script = jexl.createScript(src, "a", "b");
final Object result = script.execute(null, "a", "b");
Assertions.assertEquals("a\n?= ba\n?== b", result);
-
+ String[] locals = script.getLocalVariables();
+ Assertions.assertArrayEquals(new String[]{"c", "foo"}, locals);
final String TEST447 = "src/test/scripts/test447.jexl";
final File src447 = new File(TEST447);
final JexlScript script447 = jexl.createScript(src447);
@@ -831,31 +835,132 @@ public class Issues400Test {
}
+ @Test
+ void test450a() {
+ JexlEngine jexl0 = new
JexlBuilder().silent(false).permissions(JexlPermissions.RESTRICTED).create();
+ assertThrows(JexlException.Method.class, ()->jexl0.newInstance(
+ "org.apache.commons.jexl3.internal.introspection.Uberspect", null,
null),
+ "should not be able to create Uberspect with RESTRICTED");
+ JexlPermissions perm = new
JexlPermissions.ClassPermissions(org.apache.commons.jexl3.internal.introspection.Uberspect.class);
+ JexlEngine jexl1 = new
JexlBuilder().silent(false).permissions(perm).create();
+ assertNotNull(jexl1.newInstance(
+
"org.apache.commons.jexl3.internal.introspection.Uberspect", null, null),
+ "should able to create Uberspect with Uberspect permission");
+
+ }
+
+ @Test
+ void test450b() {
+ // cannot load System with RESTRICTED
+ assertThrows(JexlException.Method.class,
+ () -> run450b(JexlPermissions.RESTRICTED), "should not be able
to load System with RESTRICTED");
+ // can load System with UNRESTRICTED
+ assertEquals(java.lang.System.class, run450b(UNRESTRICTED));
+ // need to explicitly allow Uberspect and the current class loader to
load System
+ JexlPermissions perm = new JexlPermissions.ClassPermissions(
+ getClass().getClassLoader().getClass(),
org.apache.commons.jexl3.internal.introspection.Uberspect.class);
+ assertEquals(java.lang.System.class, run450b(perm));
+ }
+
+ private static Object run450b(JexlPermissions perm) {
+ JexlEngine jexl = new
JexlBuilder().silent(false).permissions(perm).create();
+ String uscript =
"new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null,
perm).getClassLoader().loadClass('java.lang.System')";
+ JexlScript u0 = jexl.createScript(uscript, "perm");
+ return u0.execute(null, perm);
+ }
+
+ @Test
+ void test450c() {
+ // can reach and invoke System::currentTimeMillis with UNRESTRICTED
+ assertNotNull(run450c(UNRESTRICTED));
+ // need explicit permissions to ClassPermissions and Uberspect to
reach and invoke System::currentTimeMillis
+ JexlPermissions perm = new JexlPermissions.ClassPermissions(
+ JexlPermissions.ClassPermissions.class,
+ org.apache.commons.jexl3.internal.introspection.Uberspect.class);
+ assertNotNull(run450c(perm));
+ // cannot reach and invoke System::currentTimeMillis with RESTRICTED
+ assertThrows(JxltEngine.Exception.class,
+ () -> run450c(JexlPermissions.RESTRICTED), "should not be able
to load System with RESTRICTED");
+ }
+
+ private static Object run450c(JexlPermissions perm) {
+ JexlBuilder builder = new
JexlBuilder().silent(false).permissions(perm);
+ Object result = new TemplateEngine(new Engine32(builder),false, 2,
'$', '#').createExpression(
+ "${x = new
('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null,
UNRESTRICTED);" +
+ "sys = x?.getClassLoader()?.loadClass('java.lang.System') ?:
SYSTEM;" + // fail to create uberspect with java 8
+ "p =
new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions',
[sys]);" +
+ "c =
new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null,
p);" +
+ "z = c.getMethod(sys,'currentTimeMillis').invoke(x,null);}"
+ ).evaluate(new BrkContext());
+ return result;
+ }
+
@Test
void test450() {
- for (JexlPermissions perm : new
JexlPermissions[]{JexlPermissions.RESTRICTED, JexlPermissions.UNRESTRICTED}) {
- JexlEngine jexl = new JexlBuilder().permissions(perm).create();
- JexlScript e = getExpression450(jexl);
- try {
- e.execute(null);
- fail("should not be able to access System class with " + perm);
- } catch (JexlException xjexl) {
- assertNotNull(xjexl);
- }
+ assertNotNull(run450(JexlPermissions.UNRESTRICTED),
+ "should be able to reach and invoke System::currentTimeMillis
with UNRESTRICTED");
+ assertNotNull(run450(new
JexlPermissions.ClassPermissions(org.apache.commons.jexl3.internal.TemplateEngine.class)),
+ "should be able to reach and invoke System::currentTimeMillis
with TemplateEngine permission");
+ assertThrows(JexlException.Method.class,
+ () -> run450(RESTRICTED),
+ "should not be able to reach and invoke
System::currentTimeMillis with RESTRICTED");
+ }
+
+ public static class Engine33 extends Engine32 {
+ public Engine33() {
+ this(createBuilder());
+ }
+ public Engine33(JexlBuilder builder) {
+ super(builder);
+ }
+ static JexlBuilder createBuilder() {
+ JexlPermissions perm = new JexlPermissions.ClassPermissions(
+ Issues400Test.class.getClassLoader().getClass(),
+ JexlPermissions.ClassPermissions.class,
+ org.apache.commons.jexl3.internal.TemplateEngine.class,
+
org.apache.commons.jexl3.internal.introspection.Uberspect.class);
+ return new
JexlBuilder().safe(false).silent(false).permissions(perm);
}
}
- private static JexlScript getExpression450(JexlEngine jexl) {
+ private static Object run450(JexlPermissions perm) {
+ JexlEngine jexl = new
JexlBuilder().silent(false).strict(true).safe(false).permissions(perm).create();
return
jexl.createScript("new('org.apache.commons.jexl3.internal.TemplateEngine'," +
-
"new('org.apache.commons.jexl3.internal.Engine32'),false,256,'{'.charAt(0),'#'.charAt(0))"
+
+
"new('org.apache.commons.jexl3.Issues400Test$Engine33'),false,256,'$'.charAt(0),'#'.charAt(0))"
+
".createExpression(" +
- "\"#{x = new
('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null,
UNRESTRICTED);" +
- "sys = x.getClassLoader().loadClass('java.lang.System') ?:
SYSTEM;" + // fail to load System
+ "\"#{x = new
('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null);" +
+ "sys = x?.getClassLoader().loadClass('java.lang.System')
?: SYSTEM;" + // fail to load System on Java 8
"p =
new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions',
[sys]);" +
"c =
new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null,
p);" +
"z =
c.getMethod(sys,'currentTimeMillis').invoke(x,null);}\")" +
-
".evaluate(new('org.apache.commons.jexl3.Issues400Test$BrkContext'))");
+
".evaluate(new('org.apache.commons.jexl3.Issues400Test$BrkContext'))").execute(null);
+ }
+
+ @Test
+ void test451() {
+ JexlEngine jexl = new JexlBuilder().create();
+ assertEquals("42",
+ jexl.createScript("o.toString()", "o").execute(null, "42"));
+ JexlPermissions perms = RESTRICTED.compose("java.lang { +Class {
getSimpleName(); } }");
+ JexlSandbox sandbox = new JexlSandbox(false, true);
+ sandbox.permissions(Object.class.getName(), true, true, false, false);
+ sandbox.allow(String.class.getName()).execute("toString");
+ final JexlEngine jexl451 = new
JexlBuilder().safe(false).silent(false).permissions(perms).sandbox(sandbox).create();
+ // sandbox allows String::toString
+ assertEquals("42",
+ jexl451.createScript("o.toString()", "o").execute(null, "42"));
+ // sandbox forbids getClass
+ assertThrows(JexlException.Method.class,
+ () -> jexl451.createScript("oo.getClass()",
"oo").execute(null, "42"));
+ // sandbox allows reading properties, permissions allow getClass
+ assertEquals(String.class,
+ jexl451.createScript("o.class", "o").execute(null, "42"));
+ // sandbox allows reading properties, permissions allow getSimpleName
+ assertEquals("Object",
+ jexl451.createScript("o.class.simpleName", "o").execute(null,
new Object()));
+ // sandbox allows reading properties, permissions forbids
getClassLoader
+ assertThrows(JexlException.Property.class,
+ () -> jexl451.createScript("o.class.classLoader",
"o").execute(null, new Object()));
}
-
}