1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.api.scripting.test;
27
28import static org.testng.Assert.fail;
29import java.lang.reflect.InvocationHandler;
30import java.lang.reflect.Method;
31import java.lang.reflect.Proxy;
32import javax.script.ScriptEngine;
33import javax.script.ScriptEngineManager;
34import javax.script.ScriptException;
35import jdk.nashorn.api.scripting.ClassFilter;
36import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
37import org.testng.annotations.Test;
38
39/**
40 * jsr223 tests for security access checks.
41 *
42 * @test
43 * @run testng/othervm jdk.nashorn.api.scripting.test.ScriptEngineSecurityTest
44 */
45@SuppressWarnings("javadoc")
46public class ScriptEngineSecurityTest {
47
48    private static void log(final String msg) {
49        org.testng.Reporter.log(msg, true);
50    }
51
52    @Test
53    public void securityPackagesTest() {
54        if (System.getSecurityManager() == null) {
55            // pass vacuously
56            return;
57        }
58
59        final ScriptEngineManager m = new ScriptEngineManager();
60        final ScriptEngine e = m.getEngineByName("nashorn");
61        try {
62            e.eval("var v = Packages.sun.misc.Unsafe;");
63            fail("should have thrown SecurityException");
64        } catch (final Exception exp) {
65            if (exp instanceof SecurityException) {
66                log("got " + exp + " as expected");
67            } else {
68                fail(exp.getMessage());
69            }
70        }
71    }
72
73    @Test
74    public void securityJavaTypeTest() {
75        if (System.getSecurityManager() == null) {
76            // pass vacuously
77            return;
78        }
79
80        final ScriptEngineManager m = new ScriptEngineManager();
81        final ScriptEngine e = m.getEngineByName("nashorn");
82        try {
83            e.eval("var v = Java.type('sun.misc.Unsafe');");
84            fail("should have thrown SecurityException");
85        } catch (final Exception exp) {
86            if (exp instanceof SecurityException) {
87                log("got " + exp + " as expected");
88            } else {
89                fail(exp.getMessage());
90            }
91        }
92    }
93
94    @Test
95    public void securityClassForNameTest() {
96        if (System.getSecurityManager() == null) {
97            // pass vacuously
98            return;
99        }
100
101        final ScriptEngineManager m = new ScriptEngineManager();
102        final ScriptEngine e = m.getEngineByName("nashorn");
103        try {
104            e.eval("var v = java.lang.Class.forName('sun.misc.Unsafe');");
105            fail("should have thrown SecurityException");
106        } catch (final Exception exp) {
107            if (exp instanceof SecurityException) {
108                log("got " + exp + " as expected");
109            } else {
110                fail(exp.getMessage());
111            }
112        }
113    }
114
115    @Test
116    public void securitySystemExit() {
117        if (System.getSecurityManager() == null) {
118            // pass vacuously
119            return;
120        }
121
122        final ScriptEngineManager m = new ScriptEngineManager();
123        final ScriptEngine e = m.getEngineByName("nashorn");
124        try {
125            e.eval("java.lang.System.exit(0);");
126            fail("should have thrown SecurityException");
127        } catch (final Exception exp) {
128            if (exp instanceof SecurityException) {
129                log("got " + exp + " as expected");
130            } else {
131                fail(exp.getMessage());
132            }
133        }
134    }
135
136
137    @Test
138    public void securitySystemExitFromFinalizerThread() throws ScriptException {
139        if (System.getSecurityManager() == null) {
140            // pass vacuously
141            return;
142        }
143
144        final ScriptEngineManager m = new ScriptEngineManager();
145        final ScriptEngine e = m.getEngineByName("nashorn");
146        e.eval("var o = Java.extend(Java.type('javax.imageio.spi.ServiceRegistry'), { deregisterAll: this.exit.bind(null, 1234)});\n" +
147                "new o(new java.util.ArrayList().iterator())");
148        System.gc();
149        System.runFinalization();
150        // NOTE: this test just exits the VM if it fails.
151    }
152
153    @Test
154    public void securitySystemLoadLibrary() {
155        if (System.getSecurityManager() == null) {
156            // pass vacuously
157            return;
158        }
159
160        final ScriptEngineManager m = new ScriptEngineManager();
161        final ScriptEngine e = m.getEngineByName("nashorn");
162        try {
163            e.eval("java.lang.System.loadLibrary('foo');");
164            fail("should have thrown SecurityException");
165        } catch (final Exception exp) {
166            if (exp instanceof SecurityException) {
167                log("got " + exp + " as expected");
168            } else {
169                fail(exp.getMessage());
170            }
171        }
172    }
173
174    // @bug 8032948: Nashorn linkages awry
175    @SuppressWarnings({ "serial", "deprecation" })
176    public static class FakeProxy extends Proxy {
177        public FakeProxy(final InvocationHandler ih) {
178            super(ih);
179        }
180
181        public static Class<?> makeProxyClass(final ClassLoader cl, final Class<?>... ifaces) {
182            return Proxy.getProxyClass(cl, ifaces);
183        }
184    }
185
186    @Test
187    public void fakeProxySubclassAccessCheckTest() {
188        if (System.getSecurityManager() == null) {
189            // pass vacuously
190            return;
191        }
192
193        final ScriptEngineManager m = new ScriptEngineManager();
194        final ScriptEngine e = m.getEngineByName("nashorn");
195
196        e.put("name", ScriptEngineSecurityTest.class.getName());
197        e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
198        e.put("intfs", new Class[] { Runnable.class });
199
200        final String getClass = "Java.type(name + '$FakeProxy').getProxyClass(cl, intfs);";
201
202        // Should not be able to call static methods of Proxy via fake subclass
203        try {
204            e.eval(getClass);
205            fail("should have thrown SecurityException");
206        } catch (final Exception exp) {
207            if (! (exp instanceof SecurityException)) {
208                fail("SecurityException expected, got " + exp);
209            }
210        }
211    }
212
213    @Test
214    public void fakeProxySubclassAccessCheckTest2() {
215        if (System.getSecurityManager() == null) {
216            // pass vacuously
217            return;
218        }
219
220        final ScriptEngineManager m = new ScriptEngineManager();
221        final ScriptEngine e = m.getEngineByName("nashorn");
222
223        e.put("name", ScriptEngineSecurityTest.class.getName());
224        e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
225        e.put("intfs", new Class[] { Runnable.class });
226
227        final String getClass = "Java.type(name + '$FakeProxy').makeProxyClass(cl, intfs);";
228
229        // Should not be able to call static methods of Proxy via fake subclass
230        try {
231            e.eval(getClass);
232            fail("should have thrown SecurityException");
233        } catch (final Exception exp) {
234            if (! (exp instanceof SecurityException)) {
235                fail("SecurityException expected, got " + exp);
236            }
237        }
238    }
239
240    @Test
241    public static void proxyStaticAccessCheckTest() {
242        if (System.getSecurityManager() == null) {
243            // pass vacuously
244            return;
245        }
246
247        final ScriptEngineManager m = new ScriptEngineManager();
248        final ScriptEngine e = m.getEngineByName("nashorn");
249        final Runnable r = (Runnable)Proxy.newProxyInstance(
250            ScriptEngineSecurityTest.class.getClassLoader(),
251            new Class[] { Runnable.class },
252            new InvocationHandler() {
253                @Override
254                public Object invoke(final Object p, final Method mtd, final Object[] a) {
255                    return null;
256                }
257            });
258
259        e.put("rc", r.getClass());
260        e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
261        e.put("intfs", new Class[] { Runnable.class });
262
263        // make sure static methods of Proxy is not accessible via subclass
264        try {
265            e.eval("rc.static.getProxyClass(cl, intfs)");
266            fail("Should have thrown SecurityException");
267        } catch (final Exception exp) {
268            if (! (exp instanceof SecurityException)) {
269                fail("SecurityException expected, got " + exp);
270            }
271        }
272    }
273
274
275    @Test
276    public void nashornConfigSecurityTest() {
277        if (System.getSecurityManager() == null) {
278            // pass vacuously
279            return;
280        }
281
282        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
283        try {
284            fac.getScriptEngine(new ClassFilter() {
285               @Override
286               public boolean exposeToScripts(final String name) {
287                   return true;
288               }
289            });
290            fail("SecurityException should have been thrown");
291        } catch (final SecurityException e) {
292            //empty
293        }
294    }
295
296    @Test
297    public void nashornConfigSecurityTest2() {
298        if (System.getSecurityManager() == null) {
299            // pass vacuously
300            return;
301        }
302
303        final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
304        try {
305            fac.getScriptEngine(new String[0], null, new ClassFilter() {
306               @Override
307               public boolean exposeToScripts(final String name) {
308                   return true;
309               }
310            });
311            fail("SecurityException should have been thrown");
312        } catch (final SecurityException e) {
313            //empty
314        }
315    }
316}
317