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 36d9f06b JEXL: getting ready for 3.3; - javadoc, doc final touches 36d9f06b is described below commit 36d9f06bbdced9d4775d5475d9855402988c2b82 Author: henrib <hen...@apache.org> AuthorDate: Fri Mar 10 13:20:00 2023 +0100 JEXL: getting ready for 3.3; - javadoc, doc final touches --- RELEASE-NOTES.txt | 10 +- .../jexl3/introspection/JexlPermissions.java | 31 ++--- src/site/site.xml | 4 +- src/site/xdoc/index.xml | 126 +++++++++++---------- src/site/xdoc/relnotes33.xml | 7 +- 5 files changed, 90 insertions(+), 88 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 043edcdb..29450e27 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -33,11 +33,9 @@ in breaking your application behavior ; this breaking change requires remediatio Despite the obvious inconvenience - our sincere apologies on the matter -, how much functional and semantic power is accessible through scripts has a real impact on your application security and stability ; that potential risk requires an informed review and conscious choice on your end. -To mitigate the change, you can revert to the previous behavior with one line of code (see JexlBuilder) or use this -opportunity to reduce exposure. Whether Files, URLs, networking, processes, class-loaders or reflection features are -accessible are part of the choice to make. -Any CVE linked to JEXL should try resolution by upgrading to 3.3. - +To mitigate the change, you can revert to the previous behavior with one line of code (see JexlPermissions, JexlBuilder +and JexlScriptEngine) or use this opportunity to reduce exposure. Whether Files, URLs, networking, processes, +class-loaders or reflection classes or whether loops or side-effects are accessible are part of your choice to make. What's new in 3.3: ================== @@ -45,7 +43,7 @@ JEXL 3.3 brings the ability to configure permissions on libraries in the manner with the @NoJexl annotation on source code. This is achieved through a crude but light mechanism akin to a security manager that controls what JEXL can introspect and thus expose to scripts. Used in conjunction with options (JexlOptions) and features (JexlFeatures), the permissions (JexlPermissions) -allow fine-tuning the scripting integration into any project. +allow fine-tuning the end-user freedom and scripting integration through syntactic and semantic sanitation. JEXL 3.3 also adds some syntactic (ECMAScript) features (let, const, =>, for, ...) to further reduce the skill set required to write scripts. 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 d405b6cd..3af353ed 100644 --- a/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java +++ b/src/main/java/org/apache/commons/jexl3/introspection/JexlPermissions.java @@ -54,7 +54,7 @@ import java.util.stream.Collectors; * <p> * To help migration from earlier versions, it is possible to revert to the JEXL 3.2 default lenient behavior * by calling {@link org.apache.commons.jexl3.JexlBuilder#setDefaultPermissions(JexlPermissions)} with - * {@link #UNRESTRICTED} as parameter. + * {@link #UNRESTRICTED} as parameter before creating a JEXL engine instance. * </p> * <p> * For the same reason, using JEXL through scripting, it is possible to revert the underlying JEXL behaviour to @@ -142,15 +142,17 @@ public interface JexlPermissions { * java.lang { Runtime {} System {} ProcessBuilder {} Class {} } * org.apache.commons.jexl3 { JexlBuilder {} } * </pre> - * <p> - * Syntax for wildcards is the name of the package suffixed by <code>.*</code>. Syntax for restrictions is - * a list of package restrictions. A package restriction is a package name followed by a block - * (as in curly-bracket block {}) that contains a list of class restrictions. A class restriction is a class name - * followed by a block of member restrictions. A member restriction can be a class restriction - to restrict + * <ul> + * <li>Syntax for wildcards is the name of the package suffixed by <code>.*</code>.</li> + * <li>Syntax for restrictions is a list of package restrictions.</li> + * <li>A package restriction is a package name followed by a block (as in curly-bracket block {}) + * that contains a list of class restrictions.</li> + * <li>A class restriction is a class name followed by a block of member restrictions.</li> + * <li>A member restriction can be a class restriction - to restrict * nested classes -, a field which is the Java field name suffixed with <code>;</code>, a method composed of * its Java name suffixed with <code>();</code>. Constructor restrictions are specified like methods using the - * class name as method name. - * </p> + * class name as method name.</li> + * </ul> * <p> * All overrides and overloads of a constructors or method are allowed or restricted at the same time, * the restriction being based on their names, not their whole signature. This differs from the @NoJexl annotation. @@ -190,7 +192,8 @@ public interface JexlPermissions { /** * Compose these permissions with a new set. * <p>This is a convenience method meant to easily give access to the packages JEXL is - * used to integrate with.</p> + * used to integrate with. For instance, using <code>{@link #RESTRICTED}.compose("com.my.app.*")</code> + * would extend the restricted set of permissions by allowing the com.my.app package.</p> * @param src the new constraints * @return the new permissions */ @@ -268,7 +271,7 @@ public interface JexlPermissions { /** * Checks that a package is valid for permission check. - * @param pack the palcaga + * @param pack the package * @return true if the class is not null, false otherwise */ default boolean validate(final Package pack) { @@ -286,15 +289,15 @@ public interface JexlPermissions { /** * Checks that a constructor is valid for permission check. - * @param ctor the constructor + * @param constructor the constructor * @return true if constructor is not null and public, false otherwise */ - default boolean validate(final Constructor<?> ctor) { - if (ctor == null) { + default boolean validate(final Constructor<?> constructor) { + if (constructor == null) { return false; } // field must be public - if (!Modifier.isPublic(ctor.getModifiers())) { + if (!Modifier.isPublic(constructor.getModifiers())) { return false; } return true; diff --git a/src/site/site.xml b/src/site/site.xml index eec9a22f..d17a2f96 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -25,8 +25,8 @@ <body> <menu name="JEXL"> <item name="Overview" href="index.html" /> - <item name="JEXL 3.3 Release notes" href="relnotes33.html"/> - <item name="Javadoc 3.3" href="apidocs/index.html"/> + <item name="Release Notes" href="relnotes33.html"/> + <item name="Javadoc 3.3" href="apidocs/index.html"/> <item name="Javadoc 2.1.1" href="javadocs/apidocs-2.1.1/index.html"/> <item name="Javadoc 1.1" href="javadocs/apidocs-1.1/index.html"/> <item name="Download" href="download_jexl.cgi"/> diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index d2ff2ed0..68683c7f 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -119,91 +119,93 @@ and ensure their execution within controlled functional constraints. </p> <p>The following example illustrate these aspects. It uses a specific set of permissions to allow using URI class and a tailored context to expose streams in a convenient manner.</p> - - <source><![CDATA[ - -/** + <!-- + using http://java2html.blogspot.com to prettify code, minor edits; ugly to look at a source, pretty rendered + --> + <div> +<pre style="text-align: left; border: 1px dashed #008DEF; line-height: 18px; padding: 15px; font-size: 13px; font-family:'Courier New', Courier, monospace; overflow: auto;"><span style='color:#3F5FBF'>/** * A test around scripting streams. - */ -public class StreamTest { - /** Our engine instance. */ - private final JexlEngine jexl; + */</span> +<span style='font-weight:bold;color:#7B0052;'>public</span> <span style='font-weight:bold;color:#7B0052;'>class</span> StreamTest <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='color:#3F5FBF'>/** Our engine instance. */</span> + <span style='font-weight:bold;color:#7B0052;'>private</span> <span style='font-weight:bold;color:#7B0052;'>final</span> JexlEngine jexl; - public StreamTest() { - // Restricting features; no loops, no side effects - JexlFeatures features = new JexlFeatures() - .loops(false) - .sideEffectGlobal(false) - .sideEffect(false); - // Restricted permissions to a safe set but with URI allowed - JexlPermissions permissions = new ClassPermissions(java.net.URI.class); - // Create the engine - jexl = new JexlBuilder().permissions(permissions).create(); - } + <span style='font-weight:bold;color:#7B0052;'>public</span> StreamTest() <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='color:#3F7F5F'>// Restricting features; no loops, no side effects +</span> JexlFeatures features = <span style='font-weight:bold;color:#7B0052;'>new</span> JexlFeatures() + .loops(<span style='font-weight:bold;color:#7B0052;'>false</span>) + .sideEffectGlobal(<span style='font-weight:bold;color:#7B0052;'>false</span>) + .sideEffect(<span style='font-weight:bold;color:#7B0052;'>false</span>); + <span style='color:#3F7F5F'>// Restricted permissions to a safe set but with URI allowed +</span> JexlPermissions permissions = <span style='font-weight:bold;color:#7B0052;'>new</span> ClassPermissions(java.net.URI.class); + <span style='color:#3F7F5F'>// Create the engine +</span> jexl = <span style='font-weight:bold;color:#7B0052;'>new</span> JexlBuilder().permissions(permissions).create(); + <span style='font-weight:bold;color:#D3171B'>}</span> - /** + <span style='color:#3F5FBF'>/** * A MapContext that can operate on streams. - */ - public static class StreamContext extends MapContext { - /** + */</span> + <span style='font-weight:bold;color:#7B0052;'>public</span> <span style='font-weight:bold;color:#7B0052;'>static</span> <span style='font-weight:bold;color:#7B0052;'>class</span> StreamContext <span style='font-weight:bold;color:#7B0052;'>extends</span> MapContext <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='color:#3F5FBF'>/** * This allows using a JEXL lambda as a mapper. * @param stream the stream * @param mapper the lambda to use as mapper * @return the mapped stream - */ - public Stream<?> map(Stream<?> stream, final JexlScript mapper) { - return stream.map( x -> mapper.execute(this, x)); - } + */</span> + <span style='font-weight:bold;color:#7B0052;'>public</span> Stream<?> map(Stream<?> stream, <span style='font-weight:bold;color:#7B0052;'>final</span> JexlScript mapper) <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='font-weight:bold;color:#7B0052;'>return</span> stream.map( x -> mapper.execute(this, x)); + <span style='font-weight:bold;color:#D3171B'>}</span> - /** + <span style='color:#3F5FBF'>/** * This allows using a JEXL lambda as a filter. * @param stream the stream * @param filter the lambda to use as filter * @return the filtered stream - */ - public Stream<?> filter(Stream<?> stream, final JexlScript filter) { - return stream.filter(x -> x =! null && TRUE.equals(filter.execute(this, x))); - } - } + */</span> + <span style='font-weight:bold;color:#7B0052;'>public</span> Stream<?> filter(Stream<?> stream, <span style='font-weight:bold;color:#7B0052;'>final</span> JexlScript filter) <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='font-weight:bold;color:#7B0052;'>return</span> stream.filter(x -> x =! <span style='font-weight:bold;color:#7B0052;'>null</span> "" TRUE.equals(filter.execute(this, x))); + <span style='font-weight:bold;color:#D3171B'>}</span> + <span style='font-weight:bold;color:#D3171B'>}</span> @Test - public void testURIStream() throws Exception { - // let's assume a collection of uris need to be processed and transformed to be simplified ; - // we want only http/https ones, only the host part and forcing an https scheme - List<URI> uris = Arrays.asList( - URI.create("http://u...@www.apache.org:8000?qry=true"), - URI.create("https://commons.apache.org/releases/prepare.html"), - URI.create("mailto:hen...@apache.org") + <span style='font-weight:bold;color:#7B0052;'>public</span> <span style='font-weight:bold;color:#7B0052;'>void</span> testURIStream() <span style='font-weight:bold;color:#7B0052;'>throws</span> Exception <span style='font-weight:bold;color:#D3171B'>{</span> + <span style='color:#3F7F5F'>// let's assume a collection of uris need to be processed and transformed to be simplified ; +</span> <span style='color:#3F7F5F'>// we want only http/https ones, only the host part and forcing an https scheme +</span> List<URI> uris = Arrays.asList( + URI.create(<span style='color:#2A00FF'>"http://u...@www.apache.org:8000?qry=true"</span>), + URI.create(<span style='color:#2A00FF'>"https://commons.apache.org/releases/prepare.html"</span>), + URI.create(<span style='color:#2A00FF'>"mailto:hen...@apache.org"</span>) ); - // Create the test control, the expected result of our script evaluation - List<?> control = uris.stream() - .map(uri -> uri.getScheme().startsWith("http")? "https://" + uri.getHost() : null) - .filter(x -> x != null) + <span style='color:#3F7F5F'>// Create the test control, the expected result of our script evaluation +</span> List<?> control = uris.stream() + .map(uri -> uri.getScheme().startsWith(<span style='color:#2A00FF'>"http"</span>)? <span style='color:#2A00FF'>"https://"</span> + uri.getHost() : <span style='font-weight:bold;color:#7B0052;'>null</span>) + .filter(x -> x != <span style='font-weight:bold;color:#7B0052;'>null</span>) .collect(Collectors.toList()); Assert.assertEquals(2, control.size()); - // Create scripts: - // uri is the name of the variable used as parameter; the beans are exposed as properties - // note the starts-with operator =^ - // note that uri is also used in the back-quoted string that performs variable interpolation - JexlScript mapper = jexl.createScript("uri.scheme =^ 'http'? `https://${uri.host}` : null", "uri"); - // using the bang-bang / !! - JScript like - is the way to coerce to boolean in the filter - JexlScript transform = jexl.createScript( - "list.stream().map(mapper).filter(x -> !!x).collect(Collectors.toList())", "list"); + <span style='color:#3F7F5F'>// Create scripts: +</span> <span style='color:#3F7F5F'>// uri is the name of the variable used as parameter; the beans are exposed as properties +</span> <span style='color:#3F7F5F'>// note the starts-with operator =^ +</span> <span style='color:#3F7F5F'>// note that uri is also used in the back-quoted string that performs variable interpolation +</span> JexlScript mapper = jexl.createScript(<span style='color:#2A00FF'>"uri.scheme =^ 'http'? `https://${uri.host}` : null"</span>, <span style='color:#2A00FF'>"uri"</span>); + <span style='color:#3F7F5F'>// using the bang-bang / !! - JScript like - is the way to coerce to boolean in the filter +</span> JexlScript transform = jexl.createScript( + <span style='color:#2A00FF'>"list.stream().map(mapper).filter(x -> !!x).collect(Collectors.toList())"</span>, <span style='color:#2A00FF'>"list"</span>); - // Execute scripts: - JexlContext sctxt = new StreamContext(); - // expose the static methods of Collectors; java.util.* is allowed by permissions - sctxt.set("Collectors", Collectors.class); - // expose the mapper script as a global variable in the context - sctxt.set("mapper", mapper); + <span style='color:#3F7F5F'>// Execute scripts: +</span> JexlContext sctxt = <span style='font-weight:bold;color:#7B0052;'>new</span> StreamContext(); + <span style='color:#3F7F5F'>// expose the static methods of Collectors; java.util.* is allowed by permissions +</span> sctxt.set(<span style='color:#2A00FF'>"Collectors"</span>, Collectors.class); + <span style='color:#3F7F5F'>// expose the mapper script as a global variable in the context +</span> sctxt.set(<span style='color:#2A00FF'>"mapper"</span>, mapper); Object transformed = transform.execute(sctxt, uris); - Assert.assertTrue(transformed instanceof List<?>); + Assert.assertTrue(transformed <span style='font-weight:bold;color:#7B0052;'>instanceof</span> List<?>); Assert.assertEquals(control, transformed); - } -} - ]]></source> + <span style='font-weight:bold;color:#D3171B'>}</span> +<span style='font-weight:bold;color:#D3171B'>}</span></pre> + </div> + </section> <section name="Extensions to JSTL Expression Language"> diff --git a/src/site/xdoc/relnotes33.xml b/src/site/xdoc/relnotes33.xml index 982cfa89..344d6bbd 100644 --- a/src/site/xdoc/relnotes33.xml +++ b/src/site/xdoc/relnotes33.xml @@ -38,9 +38,8 @@ (see <a href="apidocs/org/apache/commons/jexl3/introspection/JexlPermissions.html">JexlPermissions</a>, <a href="apidocs/org/apache/commons/jexl3/JexlBuilder.html">JexlBuilder</a> and <a href="apidocs/org/apache/commons/jexl3/scripting/JexlScriptEngine.html">JexlScriptEngine</a> ) or use this - opportunity to reduce exposure. Whether Files, URLs, networking, processes, class-loaders or reflection features are - accessible are part of the choice to make.</p><p> - <strong>Any CVE linked to JEXL should try resolution by first upgrading to JEXL 3.3.</strong> + opportunity to reduce exposure. Whether Files, URLs, networking, processes, class-loaders or reflection classes + or whether loops or side-effects are accessible are part of your choice to make. </p> </section> <section name="What's new in 3.3:"> @@ -50,7 +49,7 @@ a security manager that controls what JEXL can introspect and thus expose to scripts. </p><p> Used in conjunction with options (JexlOptions) and features (JexlFeatures), the permissions (JexlPermissions) - allow fine-tuning the scripting integration into any project. + allow fine-tuning the end-user freedom and scripting integration through syntactic and semantic sanitation. </p><p> JEXL 3.3 also adds some syntactic (ECMAScript) features (let, const, =>, for, ...) to further reduce the skill set required to write scripts.