1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertSame;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23
24 import org.junit.jupiter.api.AfterEach;
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27
28
29
30
31
32
33
34
35
36 public class DefaultsTest {
37
38 @BeforeEach
39 void restoreHardenedDefaults() {
40
41 JexlBuilder.setDefaultPermissions(null);
42 JexlBuilder.setDefaultFeatures(null);
43 }
44
45 @AfterEach
46 void restoreTestPermissive() {
47 JexlBuilder.setDefaultPermissions(JexlTestCase.TEST_PERMS);
48 JexlBuilder.setDefaultFeatures(JexlFeatures.createDefault());
49 }
50
51 @Test
52 void testDefaultPermissionsAreSecure() {
53 final JexlBuilder builder = new JexlBuilder();
54 assertSame(org.apache.commons.jexl3.introspection.JexlPermissions.SECURE, builder.permissions());
55 }
56
57 @Test
58 void testNewInstanceDisabledByDefault() {
59 final JexlEngine engine = new JexlBuilder().create();
60 assertThrows(JexlException.Feature.class,
61 () -> engine.createScript("new('java.util.ArrayList')"),
62 "new() must be rejected at parse time under hardened defaults");
63 }
64
65 @Test
66 void testLoopsEnabledForScriptsNotExpressions() {
67 final JexlEngine engine = new JexlBuilder().create();
68
69 assertNotNull(engine.createScript("var s = 0; for (var i : [1,2,3]) { s += i; } s"),
70 "for-loop must be accepted in a script under hardened defaults");
71
72 assertThrows(JexlException.class,
73 () -> engine.createExpression("for (var i : [1,2,3]) { i }"),
74 "for-loop must be rejected in an expression");
75 }
76
77 @Test
78 void testGlobalSideEffectDisabledByDefault() {
79 final JexlEngine engine = new JexlBuilder().create();
80 assertThrows(JexlException.Feature.class,
81 () -> engine.createScript("x = 1"),
82 "global assignment must be rejected at parse time under hardened defaults");
83 }
84
85 @Test
86 void testPragmaDisabledByDefault() {
87 final JexlEngine engine = new JexlBuilder().create();
88 assertThrows(JexlException.Feature.class,
89 () -> engine.createScript("#pragma jexl.foo 'bar'\n42"),
90 "pragma must be rejected at parse time under hardened defaults");
91 }
92
93 @Test
94 void testAnnotationDisabledByDefault() {
95 final JexlEngine engine = new JexlBuilder().create();
96 assertThrows(JexlException.Feature.class,
97 () -> engine.createScript("@silent var x = 1"),
98 "annotation must be rejected at parse time under hardened defaults");
99 }
100
101 @Test
102 void testLexicalEnabledByDefault() {
103 final JexlEngine engine = new JexlBuilder().create();
104
105 assertThrows(JexlException.class,
106 () -> engine.createScript("var x = 1; var x = 2; x"),
107 "lexical scoping must reject redeclaration under hardened defaults");
108 }
109
110 @Test
111 void testPackageDocExampleRunsUnderSecure() {
112
113 final JexlEngine jexl = new JexlBuilder().create();
114 final JexlExpression e = jexl.createExpression(
115 "'Hello ' + name + ', your name has ' + name.length() + ' letters'");
116 final JexlContext jc = new MapContext();
117 jc.set("name", "Aiko");
118 assertEquals("Hello Aiko, your name has 4 letters", e.evaluate(jc));
119 }
120
121 @Test
122 void testSecureDeniesFileAndKeepsCollections() {
123
124 final JexlEngine jexl = new JexlBuilder()
125 .permissions(org.apache.commons.jexl3.introspection.JexlPermissions.SECURE)
126 .features(JexlFeatures.createDefault())
127 .create();
128
129 assertThrows(JexlException.class,
130 () -> jexl.createScript("new('java.util.Formatter', '/tmp/jexl-should-not-exist')").execute(null),
131 "java.util.Formatter must be denied under SECURE");
132
133 final Object r = jexl.createScript(
134 "var m = {1 : 'a'}; var s = ''; for (var e : m) { s += e; } s + m.size()").execute(null);
135 assertEquals("a1", r);
136
137 assertThrows(JexlException.Method.class,
138 () -> jexl.createScript("'x'.getClass()").execute(null),
139 "getClass() must be denied under SECURE");
140 }
141
142 @Test
143 void testSecurePermsDenyRuntime() {
144 final JexlEngine engine = new JexlBuilder().features(JexlFeatures.createDefault()).create();
145
146 assertThrows(JexlException.class,
147 () -> engine.createScript("Runtime.getRuntime()").execute(new MapContext()),
148 "Runtime should be denied under SECURE permissions");
149 }
150 }