1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal.introspection;
18
19 import static org.apache.commons.jexl3.introspection.JexlPermissions.RESTRICTED;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26 import static org.junit.jupiter.api.Assertions.fail;
27
28 import java.io.FileWriter;
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.Field;
31 import java.lang.reflect.Method;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.LinkedList;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39
40 import org.apache.commons.jexl3.JexlArithmetic;
41 import org.apache.commons.jexl3.JexlBuilder;
42 import org.apache.commons.jexl3.JexlContext;
43 import org.apache.commons.jexl3.JexlEngine;
44 import org.apache.commons.jexl3.JexlException;
45 import org.apache.commons.jexl3.JexlScript;
46 import org.apache.commons.jexl3.JexlTestCase;
47 import org.apache.commons.jexl3.MapContext;
48 import org.apache.commons.jexl3.internal.introspection.nojexlpackage.Invisible;
49 import org.apache.commons.jexl3.introspection.JexlPermissions;
50 import org.apache.commons.jexl3.introspection.JexlUberspect;
51 import org.example.Pair;
52 import org.junit.jupiter.api.Test;
53
54
55
56
57 @SuppressWarnings({"unused","empty"})
58 class PermissionsTest {
59
60 public static class A {
61 public int i;
62 public A() {}
63 public int method() { return 0; }
64 }
65
66 public static class A0 extends A implements InterNoJexl0 {
67 public int i0;
68 public A0() {}
69 @Override public int method() { return 1; }
70 }
71
72 public static class A1 extends A implements InterNoJexl1 {
73 private int i1;
74 public A1() {}
75 @Override public int method() { return 2; }
76 }
77
78
79 public static class A2 extends A {
80 public A2() {}
81 @Override public int method() { return 3; }
82 }
83
84 protected static class A3 {
85 protected int i3;
86 protected A3() {}
87 int method() { return 4; }
88 }
89
90 public static class A5 implements InterNoJexl5 {
91 public A5() {}
92 @Override public int method() { return 0; }
93 }
94
95 protected static class Foo2 {
96 protected String protectedMethod() {
97 return "foo2";
98 }
99 public String publicMethod() {
100 return "foo2";
101 }
102 }
103
104 public static class Foo3 extends Foo2 {
105 @Override public String protectedMethod() {
106 return "foo3";
107 }
108 @Override public String publicMethod() {
109 return "foo3";
110 }
111 }
112
113 public static class I33Arithmetic extends JexlArithmetic {
114 public I33Arithmetic(final boolean astrict) {
115 super(astrict);
116 }
117
118
119
120
121
122
123 public double parseDouble(final String s) {
124 try {
125 return Double.parseDouble(s);
126 } catch (final NumberFormatException nfe) {
127 return Double.NaN;
128 }
129 }
130 }
131
132
133 public interface InterNoJexl0 {
134 int method();
135 }
136
137 public interface InterNoJexl1 {
138
139 int method();
140 }
141
142
143 public interface InterNoJexl5 {
144 int method();
145 }
146
147 public static class Outer {
148 public static class Inner {
149 public void callMeNot() {}
150 }
151 }
152
153 static Method getMethod(final Class<?> clazz, final String method) {
154 return Arrays.stream(clazz.getMethods()).filter(mth->mth.getName().equals(method)).findFirst().get();
155 }
156
157 JexlPermissions permissions0() {
158 final String src = " org.apache.commons.jexl3.internal.introspection { PermissionsTest { " +
159 "InterNoJexl0 { } " +
160 "InterNoJexl1 { method(); } " +
161 "A0 { A0(); i0; } " +
162 "A1 { A1(); } " +
163 "A2 { } " +
164 "InterNoJexl5 { } " +
165 "} }";
166 return JexlPermissions.parse(src);
167 }
168
169 private void runTestPermissions(final JexlPermissions p) throws Exception {
170 assertFalse(p.allow((Field) null));
171 assertFalse(p.allow((Package) null));
172 assertFalse(p.allow((Method) null));
173 assertFalse(p.allow((Constructor<?>) null));
174 assertFalse(p.allow((Class<?>) null));
175
176 assertFalse(p.allow(A2.class));
177 assertTrue(p.allow(A3.class));
178 assertTrue(p.allow(A5.class));
179
180 final Method mA = A.class.getMethod("method");
181 assertNotNull(mA);
182 final Method mA0 = A0.class.getMethod("method");
183 assertNotNull(mA0);
184 final Method mA1 = A1.class.getMethod("method");
185 assertNotNull(mA1);
186 final Method mA2 = A2.class.getMethod("method");
187 assertNotNull(mA2);
188 final Method mA3 = A2.class.getDeclaredMethod("method");
189 assertNotNull(mA3);
190
191 assertTrue(p.allow(mA));
192 assertFalse(p.allow(mA0));
193 assertFalse(p.allow(mA1));
194 assertFalse(p.allow(mA2));
195 assertFalse(p.allow(mA3));
196
197 final Field fA = A.class.getField("i");
198 assertNotNull(fA);
199 assertTrue(p.allow(fA));
200
201 final Field fA0 = A0.class.getField("i0");
202 assertNotNull(fA0);
203 assertFalse(p.allow(fA0));
204 assertFalse(p.allow(A0.class, fA0));
205 final Field fA1 = A1.class.getDeclaredField("i1");
206 assertNotNull(fA1);
207 assertFalse(p.allow(fA0));
208
209 final Constructor<?> cA = A.class.getConstructor();
210 assertNotNull(cA);
211 assertTrue(p.allow(cA));
212
213 final Constructor<?> cA0 = A0.class.getConstructor();
214 assertNotNull(cA0);
215 assertFalse(p.allow(cA0));
216
217 final Constructor<?> cA3 = A3.class.getDeclaredConstructor();
218 assertNotNull(cA3);
219 assertFalse(p.allow(cA3));
220 }
221
222 @Test
223 void testGetPackageName() {
224 final String PKG = "org.apache.commons.jexl3.internal.introspection";
225 String pkg = ClassTool.getPackageName(Outer.class);
226 assertEquals(PKG, pkg);
227 pkg = ClassTool.getPackageName(Outer.Inner.class);
228 assertEquals(PKG, pkg);
229 final Outer[] oo = {};
230 pkg = ClassTool.getPackageName(oo.getClass());
231 assertEquals(PKG, pkg);
232 final Outer.Inner[] ii = {};
233 pkg = ClassTool.getPackageName(ii.getClass());
234 assertEquals(PKG, pkg);
235 pkg = ClassTool.getPackageName(Process.class);
236 assertEquals("java.lang", pkg);
237 pkg = ClassTool.getPackageName(Integer.TYPE);
238 assertEquals("java.lang", pkg);
239 }
240
241 @Test
242 void testParsePermissions0a() {
243 final String src = "java.lang { Runtime { exit(); exec(); } }\njava.net { URL {} }";
244 final Permissions p = (Permissions) JexlPermissions.parse(src);
245 final Map<String, Permissions.NoJexlPackage> nojexlmap = p.getPackages();
246 assertNotNull(nojexlmap);
247 final Permissions.NoJexlPackage njp = nojexlmap.get("java.lang");
248 assertNotNull(njp);
249 final Method exit = getMethod(java.lang.Runtime.class,"exit");
250 assertNotNull(exit);
251 assertFalse(p.allow(exit));
252 final Method exec = getMethod(java.lang.Runtime.class,"exec");
253 assertNotNull(exec);
254 assertFalse(p.allow(exec));
255 final Method avp = getMethod(java.lang.Runtime.class,"availableProcessors");
256 assertNotNull(avp);
257 assertTrue(p.allow(avp));
258 final JexlUberspect uber = new Uberspect(null, null, p);
259 assertNull(uber.getClassByName("java.net.URL"));
260 }
261
262 @Test
263 void testParsePermissions0b() {
264 final String src = "java.lang { -Runtime { exit(); } }";
265 final Permissions p = (Permissions) JexlPermissions.parse(src);
266 final Method exit = getMethod(java.lang.Runtime.class,"exit");
267 assertNotNull(exit);
268 assertFalse(p.allow(exit));
269 }
270
271 @Test
272 void testParsePermissions0a2() {
273
274 final String src = "java.lang.*\njava.lang { Runtime { exit(); exec(); } }";
275 final Permissions p = (Permissions) JexlPermissions.parse(src);
276 assertTrue(p.allow(Runtime.class));
277 assertFalse(p.allow(getMethod(Runtime.class, "exit")));
278 assertTrue(p.allow(getMethod(Runtime.class, "availableProcessors")));
279 }
280
281 @Test
282 void testParsePermissions0b2() {
283
284 final String src = "java.lang +{ -Runtime { exit(); } }";
285 final Permissions p = (Permissions) JexlPermissions.parse(src);
286 assertTrue(p.allow(Runtime.class));
287 final Method exit = getMethod(Runtime.class, "exit");
288 assertNotNull(exit);
289 assertFalse(p.allow(exit));
290 final Method avp = getMethod(Runtime.class, "availableProcessors");
291 assertNotNull(avp);
292 assertTrue(p.allow(avp));
293 assertTrue(p.allow(String.class));
294 }
295
296 @Test
297 void testFormatterCtorDenied() throws Exception {
298
299 final Constructor<?> ctor = java.util.Formatter.class.getConstructor();
300 assertNotNull(ctor);
301 assertFalse(RESTRICTED.allow(ctor));
302 final Method format = getMethod(java.util.Formatter.class, "format");
303 assertNotNull(format);
304 assertTrue(RESTRICTED.allow(format));
305 assertTrue(RESTRICTED.allow(java.util.Formatter.class));
306 }
307
308 @Test
309 void testPrintWriterCtorDenied() {
310
311 for (final Constructor<?> ctor : java.io.PrintWriter.class.getDeclaredConstructors()) {
312 assertFalse(RESTRICTED.allow(ctor), () -> "should deny " + ctor);
313 }
314 final Method println = getMethod(java.io.PrintWriter.class, "println");
315 assertNotNull(println);
316 assertTrue(RESTRICTED.allow(println));
317 assertTrue(RESTRICTED.allow(java.io.PrintWriter.class));
318
319 assertFalse(RESTRICTED.allow(java.io.File.class));
320 }
321
322 @Test
323 void testForeignTypeRequiresExplicitAllow() {
324
325
326 assertFalse(RESTRICTED.allow(com.google.gson.internal.LinkedTreeMap.class));
327
328 final JexlPermissions allowed = RESTRICTED.compose("com.google.gson.internal +{}");
329 assertTrue(allowed.allow(com.google.gson.internal.LinkedTreeMap.class));
330
331 assertFalse(RESTRICTED.allow(java.lang.annotation.ElementType.class));
332 }
333
334 @Test
335 void testPositivePackageNoSubPackageWildcard() {
336
337 assertFalse(RESTRICTED.allow(java.util.zip.ZipEntry.class));
338 }
339
340 @Test
341 void testSecureMinimum() throws Exception {
342 final JexlPermissions secure = JexlPermissions.SECURE;
343
344 assertTrue(secure.allow(String.class));
345 assertTrue(secure.allow(Integer.class));
346 assertTrue(secure.allow(java.util.ArrayList.class));
347 assertTrue(secure.allow(java.util.HashMap.class));
348 assertTrue(secure.allow(java.math.BigInteger.class));
349 assertTrue(secure.allow(getMethod(Integer.class, "intValue")));
350 assertTrue(secure.allow(getMethod(java.math.BigInteger.class, "bitLength")));
351
352 assertTrue(secure.allow(getMethod(Object.class, "toString")));
353 assertFalse(secure.allow(getMethod(Object.class, "getClass")));
354
355 assertFalse(secure.allow(System.class));
356 assertFalse(secure.allow(Runtime.class));
357 assertFalse(secure.allow(java.lang.Class.class));
358 assertFalse(secure.allow(java.io.File.class));
359 assertFalse(secure.allow(java.util.zip.ZipEntry.class));
360 assertFalse(secure.allow(java.time.LocalDate.class));
361 }
362
363 @Test
364 void testNoneDeniesEverything() throws Exception {
365 final JexlPermissions none = JexlPermissions.NONE;
366 assertFalse(none.allow(String.class));
367 assertFalse(none.allow(Integer.class));
368 assertFalse(none.allow(Object.class));
369 assertFalse(none.allow(java.util.ArrayList.class));
370 assertFalse(none.allow(getMethod(String.class, "length")));
371 for (final java.lang.reflect.Constructor<?> ctor : String.class.getConstructors()) {
372 assertFalse(none.allow(ctor));
373 }
374 }
375
376 @Test
377 void testCreateFromScratch() throws Exception {
378
379 assertFalse(JexlPermissions.create().allow(String.class));
380
381 final JexlPermissions onlyString = JexlPermissions.create("java.lang { +String{} }");
382 assertTrue(onlyString.allow(String.class));
383 assertTrue(onlyString.allow(getMethod(String.class, "length")));
384 assertFalse(onlyString.allow(Integer.class));
385 assertFalse(onlyString.allow(java.util.ArrayList.class));
386
387 final JexlPermissions onlyUtil = JexlPermissions.NONE.compose("java.util.*");
388 assertTrue(onlyUtil.allow(java.util.ArrayList.class));
389 assertFalse(onlyUtil.allow(String.class));
390 }
391
392 @Test
393 void testRestrictedNoFileMethods() throws Exception {
394 final JexlPermissions r = RESTRICTED;
395
396 assertFalse(r.allow(getMethod(java.util.Properties.class, "load")));
397 assertFalse(r.allow(getMethod(java.util.Properties.class, "store")));
398 assertFalse(r.allow(getMethod(java.util.Properties.class, "loadFromXML")));
399 assertFalse(r.allow(getMethod(java.util.ResourceBundle.class, "getBundle")));
400 assertFalse(r.allow(getMethod(java.util.ServiceLoader.class, "load")));
401 for (final java.lang.reflect.Constructor<?> ctor : java.util.Scanner.class.getConstructors()) {
402 assertFalse(r.allow(ctor), () -> "Scanner ctor must be denied: " + ctor);
403 }
404
405 assertTrue(r.allow(java.util.Properties.class));
406 assertTrue(r.allow(java.util.Scanner.class));
407 assertTrue(r.allow(java.util.ResourceBundle.class));
408 assertTrue(r.allow(getMethod(java.util.Properties.class, "getProperty")));
409 assertTrue(r.allow(getMethod(java.util.ResourceBundle.class, "getString")));
410
411 assertFalse(r.allow(getMethod(Integer.class, "getInteger")));
412 assertFalse(r.allow(getMethod(Long.class, "getLong")));
413 assertFalse(r.allow(getMethod(Boolean.class, "getBoolean")));
414 assertTrue(r.allow(Integer.class));
415 assertTrue(r.allow(getMethod(Integer.class, "intValue")));
416 }
417
418 @Test
419 void testSecureNoFileNoEnv() throws Exception {
420 final JexlPermissions secure = JexlPermissions.SECURE;
421
422 assertFalse(secure.allow(java.util.Formatter.class));
423 assertFalse(secure.allow(java.util.Scanner.class));
424 assertFalse(secure.allow(java.util.ServiceLoader.class));
425 assertFalse(secure.allow(java.util.ResourceBundle.class));
426 assertFalse(secure.allow(java.util.Properties.class));
427 assertFalse(secure.allow(java.util.Timer.class));
428
429 for (final java.lang.reflect.Constructor<?> ctor : java.util.Formatter.class.getConstructors()) {
430 assertFalse(secure.allow(ctor), () -> "Formatter ctor must be denied: " + ctor);
431 }
432
433 assertFalse(secure.allow(String.class, getMethod(Object.class, "getClass")));
434 assertFalse(secure.allow(Integer.class, getMethod(Object.class, "getClass")));
435 assertFalse(secure.allow(String.class, getMethod(Object.class, "notify")));
436
437 assertFalse(secure.allow(getMethod(Integer.class, "getInteger")));
438 assertFalse(secure.allow(getMethod(Long.class, "getLong")));
439 assertFalse(secure.allow(getMethod(Boolean.class, "getBoolean")));
440
441 assertTrue(secure.allow(java.util.LinkedHashMap.class));
442 assertTrue(secure.allow(java.util.HashSet.class));
443 assertTrue(secure.allow(java.util.LinkedHashSet.class));
444 final java.util.Map<String, String> m = new java.util.HashMap<>();
445 m.put("a", "b");
446 final java.util.Map.Entry<String, String> e = m.entrySet().iterator().next();
447 assertTrue(secure.allow(e.getClass()), () -> "map entry concrete class must be reachable: " + e.getClass());
448 assertTrue(secure.allow(e.getClass(), getMethod(e.getClass(), "getKey")));
449 }
450
451 @Test
452 void testRangeIteratesUnderRestrictedAndSecure() {
453
454 for (final JexlPermissions p : new JexlPermissions[] { RESTRICTED, JexlPermissions.SECURE }) {
455 final JexlEngine jexl = new JexlBuilder().permissions(p).create();
456 final Object r = jexl.createScript("var s = 0; for (var i : 1..3) { s += i; } s").execute(null);
457 assertEquals(6, ((Number) r).intValue(), () -> "range should iterate under " + p);
458 }
459 }
460
461 @Test
462 void testParsePermissions0c() {
463 final String src = "java.lang { +Runtime { availableProcessorCount(); } }";
464 final Permissions p = (Permissions) JexlPermissions.parse(src);
465 final Method exit = getMethod(java.lang.Runtime.class,"exit");
466 assertNotNull(exit);
467 assertFalse(p.allow(exit));
468 }
469
470 @Test
471 void testParsePermissions0d() throws Exception {
472 final String src = "java.lang { +System { currentTimeMillis(); } }";
473 final JexlPermissions p = RESTRICTED.compose(src);
474 final Field in = System.class.getField("in");
475 assertNotNull(in);
476 assertFalse(p.allow(in));
477 final Method ctm = getMethod(java.lang.System.class,"currentTimeMillis");
478 assertNotNull(ctm);
479 assertTrue(p.allow(ctm));
480 }
481
482 @Test
483 void testParsePermissions0e() throws Exception {
484 final String src = "java.lang { +System { in; } }";
485 final JexlPermissions p = RESTRICTED.compose(src);
486 final Field in = System.class.getField("in");
487 assertNotNull(in);
488 assertTrue(p.allow(in));
489 final Method ctm = getMethod(java.lang.System.class,"currentTimeMillis");
490 assertNotNull(ctm);
491 assertFalse(p.allow(ctm));
492 }
493
494 @Test
495 void testParsePermissions0f() {
496 final String src = "java.lang { +Class { getName(); getSimpleName(); } }";
497 final JexlPermissions p = RESTRICTED.compose(src);
498 final Method getName = getMethod(java.lang.Class.class,"getName");
499 assertNotNull(getName);
500 assertTrue(p.allow(getName));
501 assertFalse(RESTRICTED.allow(getName));
502 final Method getSimpleName = getMethod(java.lang.Class.class,"getSimpleName");
503 assertNotNull(getSimpleName);
504 assertTrue(p.allow(getSimpleName));
505 assertFalse(RESTRICTED.allow(getSimpleName));
506
507 final Method getMethod = getMethod(java.lang.Class.class,"getMethod");
508 assertNotNull(getMethod);
509 assertFalse(p.allow(getMethod));
510
511 final Method exit = getMethod(java.lang.Runtime.class,"exit");
512 assertNotNull(exit);
513 assertFalse(p.allow(exit));
514 }
515
516 @Test
517 void testParsePermissions0g() {
518 final String src = "java.lang { +Class { } }";
519 final JexlPermissions p = RESTRICTED.compose(src);
520 final Method getName = getMethod(java.lang.Class.class,"getName");
521 assertNotNull(getName);
522 assertTrue(p.allow(getName));
523 final Method getMethod = getMethod(java.lang.Class.class,"getMethod");
524 assertNotNull(getMethod);
525 assertTrue(p.allow(getMethod));
526
527 final Method exit = getMethod(java.lang.Runtime.class,"exit");
528 assertNotNull(exit);
529 assertFalse(p.allow(exit));
530 }
531
532 @Test
533 void testParsePermissions1() {
534 final String[] src = {
535 "java.lang.*",
536 "java.math.*",
537 "java.text.*",
538 "java.util.*",
539 "java.lang { Runtime {} }",
540 "java.rmi {}",
541 "java.io { File {} }",
542 "java.nio { Path {} }" ,
543 "org.apache.commons.jexl3.internal.introspection { " +
544 "PermissionsTest { #level 0\n" +
545 " Outer { #level 1\n" +
546 " Inner { #level 2\n" +
547 " callMeNot();" +
548 " }" +
549 " }" +
550 " }" +
551 " }"};
552 final Permissions p = (Permissions) JexlPermissions.parse(src);
553 final Map<String, Permissions.NoJexlPackage> nojexlmap = p.getPackages();
554 assertNotNull(nojexlmap);
555 final Set<String> wildcards = p.getWildcards();
556 assertEquals(4, wildcards.size());
557
558 final JexlEngine jexl = new JexlBuilder().permissions(p).safe(false).lexical(true).create();
559 final Class<?> longz = Long.TYPE;
560 assertTrue(p.allow(longz));
561 final Method exit = getMethod(java.lang.Runtime.class,"exit");
562 assertNotNull(exit);
563 assertFalse(p.allow(exit));
564 final Method exec = getMethod(java.lang.Runtime.class,"getRuntime");
565 assertNotNull(exec);
566 assertFalse(p.allow(exec));
567 final Method callMeNot = getMethod(Outer.Inner.class, "callMeNot");
568 assertNotNull(callMeNot);
569 assertFalse(p.allow(callMeNot));
570 final JexlScript script = jexl.createScript("o.callMeNot()", "o");
571 assertEquals("callMeNot", assertThrows(JexlException.Method.class, () -> script.execute(null, new Outer.Inner())).getMethod());
572 final Method uncallable = getMethod(Invisible.class, "uncallable");
573 assertFalse(p.allow(uncallable));
574 final Package ip = Invisible.class.getPackage();
575 assertFalse(p.allow(ip));
576 final JexlScript script2 = jexl.createScript("o.uncallable()", "o");
577 assertEquals("uncallable", assertThrows(JexlException.Method.class, () -> script2.execute(null, new Invisible())).getMethod());
578 }
579
580 @Test
581 void testParsePermissionsFailures() {
582
583 final String[] srcs = {
584 "java.lang.*.*",
585 "java.math.*.",
586 "java.text.*;",
587 "java.lang {{ Runtime {} }",
588 "java.rmi {}}",
589 "java.io { Text File {} }",
590 "java.io { File { m.x } }",
591
592 "java.io { File { + -m(); } }",
593 "java.io { File { - +f; } }"
594 };
595
596 for (final String src : srcs) {
597 assertThrows(IllegalStateException.class, () -> JexlPermissions.parse(src));
598 }
599 }
600
601 @Test
602 void testInnerClassDenySign() {
603
604
605 final String pkg = "org.apache.commons.jexl3.internal.introspection";
606 final String src = pkg + " { PermissionsTest { +Outer { -Inner {} } } }";
607 final Permissions p = (Permissions) JexlPermissions.parse(src);
608 final Method callMeNot = getMethod(Outer.Inner.class, "callMeNot");
609 assertFalse(p.allow(callMeNot), "-Inner must be denied");
610 }
611
612 @Test
613 void testPositiveMemberDoesNotLeakToInnerClass() {
614
615
616 final String pkg = "org.apache.commons.jexl3.internal.introspection";
617 final String src = pkg + " { PermissionsTest { Outer { +hashCode(); Inner {} } } }";
618 final Permissions p = (Permissions) JexlPermissions.parse(src);
619 final Method callMeNot = getMethod(Outer.Inner.class, "callMeNot");
620 assertFalse(p.allow(callMeNot), "Inner must stay denied despite a preceding +member");
621 }
622
623 @Test
624 void testEngineCompilerDeniedUnderRestricted() {
625
626 assertFalse(RESTRICTED.allow(getMethod(JexlEngine.class, "createScript")));
627 assertFalse(RESTRICTED.allow(getMethod(JexlEngine.class, "createExpression")));
628 assertFalse(RESTRICTED.allow(getMethod(JexlEngine.class, "createJxltEngine")));
629 assertFalse(RESTRICTED.allow(getMethod(JexlEngine.class, "getThreadEngine")));
630
631 final JexlEngine jexl = new JexlBuilder().permissions(RESTRICTED).safe(false).strict(true).create();
632 final JexlContext ctxt = new MapContext();
633 ctxt.set("e", jexl);
634 final JexlScript script = jexl.createScript("e.createScript('1 + 1')");
635 assertThrows(JexlException.Method.class, () -> script.execute(ctxt));
636 }
637
638 @Test
639 void testPermissions0() throws Exception {
640 runTestPermissions(permissions0());
641 }
642
643 @Test
644 void testPermissions1() throws Exception {
645 runTestPermissions(new JexlPermissions.Delegate(permissions0()) {
646 @Override public String toString() {
647 return "delegate:" + base.toString();
648 }
649 });
650 }
651
652 @Test
653 void testPermissions2() throws Exception {
654 runTestPermissions(new JexlPermissions.ClassPermissions(permissions0(), Collections.emptySet()));
655 }
656
657 @Test void testPrivateOverload1() {
658 final String src = "parseDouble(\"PHM1\".substring(3)).intValue()";
659 final JexlArithmetic jexla = new I33Arithmetic(true);
660 final JexlEngine jexl = new JexlBuilder().safe(false).arithmetic(jexla).create();
661 final JexlScript script = jexl.createScript(src);
662 assertNotNull(script);
663 final Object result = script.execute(null);
664 assertEquals(1, result);
665 }
666
667 @Test void testProtectedOverride0() {
668 JexlScript script;
669 Object r;
670 final Foo2 foo3 = new Foo3();
671 final JexlEngine jexl = new JexlBuilder().safe(false).create();
672
673 final Foo2 foo2 = new Foo2();
674 script = jexl.createScript("x.protectedMethod()", "x");
675 assertThrows(JexlException.class, () -> script.execute(null, foo2), "protectedMethod() is not public through superclass Foo2");
676
677 r = script.execute(null, foo3);
678 assertEquals("foo3",r);
679 }
680
681 @Test void testProtectedOverride1() {
682 final List<String> a = new LinkedList<>();
683 a.add("aaa");
684 a.add("bbb");
685
686 final String src = "a.clone()";
687 final JexlEngine jexl = new JexlBuilder().safe(true).create();
688 final JexlScript script = jexl.createScript(src);
689 final JexlContext context = new MapContext();
690 context.set("a", a);
691 final Object result = script.execute(context, a);
692 assertNotNull(result);
693 }
694
695 @Test
696 void testSecurePermissions() {
697 assertNotNull(JexlTestCase.TEST_PERMS);
698 final List<Class<?>> acs = Arrays.asList(
699 java.lang.Runtime.class,
700 java.math.BigDecimal.class,
701 java.text.SimpleDateFormat.class,
702 java.util.Map.class);
703 for(final Class<?> ac: acs) {
704 final Package p = ac.getPackage();
705 assertNotNull(p, ac::getName);
706 assertTrue(JexlTestCase.TEST_PERMS.allow(p), ac::getName);
707 }
708 final List<Class<?>> nacs = Arrays.asList(
709 java.lang.annotation.ElementType.class,
710 java.lang.instrument.ClassDefinition.class,
711 java.lang.invoke.CallSite.class,
712 java.lang.management.BufferPoolMXBean.class,
713 java.lang.ref.SoftReference.class,
714 java.lang.reflect.Method.class);
715 for(final Class<?> nac : nacs) {
716 assertFalse(JexlTestCase.TEST_PERMS.allow(nac), nac::getName);
717 final Package p = nac.getPackage();
718 assertNotNull(p, nac::getName);
719 assertFalse(JexlTestCase.TEST_PERMS.allow(p), nac::getName);
720 }
721 }
722
723 @Test
724 void testWildCardPackages() {
725 Set<String> wildcards;
726 boolean found;
727 wildcards = Collections.singleton("com.apache.*");
728 found = Permissions.wildcardAllow(wildcards, "com.apache.commons.jexl3");
729 assertTrue(found);
730 found = Permissions.wildcardAllow(wildcards, "com.google.spexl");
731 assertFalse(found);
732 }
733
734 public static class Scheme {
735 public Pair cons(final Object first, final Object second) {
736 return new Pair(first, second);
737 }
738 }
739
740 @Test
741 void testPair0() throws Exception {
742 final Map<String, Object> funcs = new HashMap<>();
743 funcs.put("lisp", new Scheme());
744 final JexlPermissions permissions = JexlPermissions.RESTRICTED.compose(
745 "org.example.*",
746 "org.apache.commons.jexl3.internal.introspection { +PermissionsTest$Scheme {} }");
747 assertTrue(permissions.allow(Scheme.class.getMethod("cons", Object.class, Object.class)));
748 final JexlEngine jexl = new JexlBuilder().cache(8).permissions(permissions).namespaces(funcs).create();
749 String src = "let p = lisp:cons(17, 25); p.car + p.cdr;";
750 JexlScript script = jexl.createScript(src);
751 assertEquals(42, script.execute(null));
752 assertEquals(42, script.execute(null));
753 src = "(p, x, y) -> { p.car = x; p.cdr = y; }";
754 final Pair p = new Pair(-1, -41);
755 script = jexl.createScript(src);
756 assertNotNull(script.execute(null, p, 22, 20));
757 assertEquals(22, p.car);
758 assertEquals(20, p.cdr);
759 assertNotNull(script.execute(null, p, 18, 24));
760 assertEquals(18, p.car);
761 assertEquals(24, p.cdr);
762 }
763
764 @Test
765 void testPair1() {
766 final Map<String, Object> funcs = new HashMap<>();
767 final JexlPermissions permissions = JexlPermissions.RESTRICTED.compose("org.example.*");
768 final JexlEngine jexl = new JexlBuilder().cache(8).permissions(permissions).namespaces(funcs).create();
769 final String src = "import org.example.Pair; new Pair(17, 25);";
770 final JexlScript script = jexl.createScript(src);
771 assertThrows(JexlException.class, ()-> script.execute(null));
772 }
773
774 @Test
775 void testPermissions457a() {
776 assertTrue(RESTRICTED.allow(Long.TYPE));
777 for (final Constructor<?> ctor : FileWriter.class.getDeclaredConstructors()) {
778 assertFalse(RESTRICTED.allow(ctor));
779 }
780 for (final Method m : FileWriter.class.getMethods()) {
781 if (m.getName().equals("write")) {
782 assertTrue(RESTRICTED.allow(m), m.toString());
783 }
784 }
785 }
786
787 @Test
788 void testPermissions457b() {
789 final JexlEngine jexl = new JexlBuilder().silent(false).permissions(RESTRICTED).create();
790 final List<String> srcs = Arrays.asList(
791 "new('java.io.FileWriter', 'test.txt')",
792 "new('java.io.FileWriter', 'test.txt', true)",
793 "new('java.io.FileWriter', new java.io.File('test.txt'))",
794 "new('java.io.FileWriter', new java.io.File('test.txt'), true)",
795 "import java.io.FileWriter; new FileWriter('test.txt')"
796 );
797 for (final String src : srcs) {
798 final JexlScript script = jexl.createScript(src);
799 try {
800 script.execute(null);
801 fail("should have thrown a permission exception");
802 } catch (final JexlException.Method exception) {
803 assertTrue(exception.getMethod().contains("File"), "FileWriter::new should not be allowed");
804 }
805 }
806 }
807
808 @Test
809 void testPermissions457c() {
810 final JexlEngine jexl = new JexlBuilder().silent(false).permissions(RESTRICTED).create();
811 final List<String> srcs = Arrays.asList(
812 "new('java.io.FileReader','test.txt')",
813 "new('java.io.FileReader', new java.io.File('test.txt'))",
814 "import java.io.FileReader; new FileReader('test.txt')");
815 for (final String src : srcs) {
816 final JexlScript script = jexl.createScript(src);
817 try {
818 script.execute(null);
819 fail("should have thrown a permission exception");
820 } catch (final JexlException.Method exception) {
821 assertTrue(exception.getMethod().contains("File"), "FileReader::new should not be allowed");
822 }
823 }
824 }
825 }