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 
  26 package jdk.nashorn.api.scripting.test;
  27 
  28 import static org.testng.Assert.fail;
  29 import java.lang.reflect.InvocationHandler;
  30 import java.lang.reflect.Method;
  31 import java.lang.reflect.Proxy;
  32 import javax.script.ScriptEngine;
  33 import javax.script.ScriptEngineManager;
  34 import javax.script.ScriptException;
  35 import jdk.nashorn.api.scripting.ClassFilter;
  36 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
  37 import org.testng.annotations.Test;
  38 
  39 /**
  40  * jsr223 tests for security access checks.
  41  */
  42 @SuppressWarnings("javadoc")
  43 public class ScriptEngineSecurityTest {
  44 
  45     private static void log(final String msg) {
  46         org.testng.Reporter.log(msg, true);
  47     }
  48 
  49     @Test
  50     public void securityPackagesTest() {
  51         if (System.getSecurityManager() == null) {
  52             // pass vacuously
  53             return;
  54         }
  55 
  56         final ScriptEngineManager m = new ScriptEngineManager();
  57         final ScriptEngine e = m.getEngineByName("nashorn");
  58         try {
  59             e.eval("var v = Packages.sun.misc.Unsafe;");
  60             fail("should have thrown SecurityException");
  61         } catch (final Exception exp) {
  62             if (exp instanceof SecurityException) {
  63                 log("got " + exp + " as expected");
  64             } else {
  65                 fail(exp.getMessage());
  66             }
  67         }
  68     }
  69 
  70     @Test
  71     public void securityJavaTypeTest() {
  72         if (System.getSecurityManager() == null) {
  73             // pass vacuously
  74             return;
  75         }
  76 
  77         final ScriptEngineManager m = new ScriptEngineManager();
  78         final ScriptEngine e = m.getEngineByName("nashorn");
  79         try {
  80             e.eval("var v = Java.type('sun.misc.Unsafe');");
  81             fail("should have thrown SecurityException");
  82         } catch (final Exception exp) {
  83             if (exp instanceof SecurityException) {
  84                 log("got " + exp + " as expected");
  85             } else {
  86                 fail(exp.getMessage());
  87             }
  88         }
  89     }
  90 
  91     @Test
  92     public void securityClassForNameTest() {
  93         if (System.getSecurityManager() == null) {
  94             // pass vacuously
  95             return;
  96         }
  97 
  98         final ScriptEngineManager m = new ScriptEngineManager();
  99         final ScriptEngine e = m.getEngineByName("nashorn");
 100         try {
 101             e.eval("var v = java.lang.Class.forName('sun.misc.Unsafe');");
 102             fail("should have thrown SecurityException");
 103         } catch (final Exception exp) {
 104             if (exp instanceof SecurityException) {
 105                 log("got " + exp + " as expected");
 106             } else {
 107                 fail(exp.getMessage());
 108             }
 109         }
 110     }
 111 
 112     @Test
 113     public void securitySystemExit() {
 114         if (System.getSecurityManager() == null) {
 115             // pass vacuously
 116             return;
 117         }
 118 
 119         final ScriptEngineManager m = new ScriptEngineManager();
 120         final ScriptEngine e = m.getEngineByName("nashorn");
 121         try {
 122             e.eval("java.lang.System.exit(0);");
 123             fail("should have thrown SecurityException");
 124         } catch (final Exception exp) {
 125             if (exp instanceof SecurityException) {
 126                 log("got " + exp + " as expected");
 127             } else {
 128                 fail(exp.getMessage());
 129             }
 130         }
 131     }
 132 
 133 
 134     @Test
 135     public void securitySystemExitFromFinalizerThread() throws ScriptException {
 136         if (System.getSecurityManager() == null) {
 137             // pass vacuously
 138             return;
 139         }
 140 
 141         final ScriptEngineManager m = new ScriptEngineManager();
 142         final ScriptEngine e = m.getEngineByName("nashorn");
 143         e.eval("var o = Java.extend(Java.type('javax.imageio.spi.ServiceRegistry'), { deregisterAll: this.exit.bind(null, 1234)});\n" +
 144                 "new o(new java.util.ArrayList().iterator())");
 145         System.gc();
 146         System.runFinalization();
 147         // NOTE: this test just exits the VM if it fails.
 148     }
 149 
 150     @Test
 151     public void securitySystemLoadLibrary() {
 152         if (System.getSecurityManager() == null) {
 153             // pass vacuously
 154             return;
 155         }
 156 
 157         final ScriptEngineManager m = new ScriptEngineManager();
 158         final ScriptEngine e = m.getEngineByName("nashorn");
 159         try {
 160             e.eval("java.lang.System.loadLibrary('foo');");
 161             fail("should have thrown SecurityException");
 162         } catch (final Exception exp) {
 163             if (exp instanceof SecurityException) {
 164                 log("got " + exp + " as expected");
 165             } else {
 166                 fail(exp.getMessage());
 167             }
 168         }
 169     }
 170 
 171     // @bug 8032948: Nashorn linkages awry
 172     @SuppressWarnings("serial")
 173     public static class FakeProxy extends Proxy {
 174         public FakeProxy(final InvocationHandler ih) {
 175             super(ih);
 176         }
 177 
 178         public static Class<?> makeProxyClass(final ClassLoader cl, final Class<?>... ifaces) {
 179             return Proxy.getProxyClass(cl, ifaces);
 180         }
 181     }
 182 
 183     @Test
 184     public void fakeProxySubclassAccessCheckTest() {
 185         if (System.getSecurityManager() == null) {
 186             // pass vacuously
 187             return;
 188         }
 189 
 190         final ScriptEngineManager m = new ScriptEngineManager();
 191         final ScriptEngine e = m.getEngineByName("nashorn");
 192 
 193         e.put("name", ScriptEngineSecurityTest.class.getName());
 194         e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
 195         e.put("intfs", new Class[] { Runnable.class });
 196 
 197         final String getClass = "Java.type(name + '$FakeProxy').getProxyClass(cl, intfs);";
 198 
 199         // Should not be able to call static methods of Proxy via fake subclass
 200         try {
 201             e.eval(getClass);
 202             fail("should have thrown SecurityException");
 203         } catch (final Exception exp) {
 204             if (! (exp instanceof SecurityException)) {
 205                 fail("SecurityException expected, got " + exp);
 206             }
 207         }
 208     }
 209 
 210     @Test
 211     public void fakeProxySubclassAccessCheckTest2() {
 212         if (System.getSecurityManager() == null) {
 213             // pass vacuously
 214             return;
 215         }
 216 
 217         final ScriptEngineManager m = new ScriptEngineManager();
 218         final ScriptEngine e = m.getEngineByName("nashorn");
 219 
 220         e.put("name", ScriptEngineSecurityTest.class.getName());
 221         e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
 222         e.put("intfs", new Class[] { Runnable.class });
 223 
 224         final String getClass = "Java.type(name + '$FakeProxy').makeProxyClass(cl, intfs);";
 225 
 226         // Should not be able to call static methods of Proxy via fake subclass
 227         try {
 228             e.eval(getClass);
 229             fail("should have thrown SecurityException");
 230         } catch (final Exception exp) {
 231             if (! (exp instanceof SecurityException)) {
 232                 fail("SecurityException expected, got " + exp);
 233             }
 234         }
 235     }
 236 
 237     @Test
 238     public static void proxyStaticAccessCheckTest() {
 239         if (System.getSecurityManager() == null) {
 240             // pass vacuously
 241             return;
 242         }
 243 
 244         final ScriptEngineManager m = new ScriptEngineManager();
 245         final ScriptEngine e = m.getEngineByName("nashorn");
 246         final Runnable r = (Runnable)Proxy.newProxyInstance(
 247             ScriptEngineTest.class.getClassLoader(),
 248             new Class[] { Runnable.class },
 249             new InvocationHandler() {
 250                 @Override
 251                 public Object invoke(final Object p, final Method mtd, final Object[] a) {
 252                     return null;
 253                 }
 254             });
 255 
 256         e.put("rc", r.getClass());
 257         e.put("cl", ScriptEngineSecurityTest.class.getClassLoader());
 258         e.put("intfs", new Class[] { Runnable.class });
 259 
 260         // make sure static methods of Proxy is not accessible via subclass
 261         try {
 262             e.eval("rc.static.getProxyClass(cl, intfs)");
 263             fail("Should have thrown SecurityException");
 264         } catch (final Exception exp) {
 265             if (! (exp instanceof SecurityException)) {
 266                 fail("SecurityException expected, got " + exp);
 267             }
 268         }
 269     }
 270 
 271 
 272     @Test
 273     public void nashornConfigSecurityTest() {
 274         if (System.getSecurityManager() == null) {
 275             // pass vacuously
 276             return;
 277         }
 278 
 279         final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
 280         try {
 281             fac.getScriptEngine(new ClassFilter() {
 282                @Override
 283                public boolean exposeToScripts(final String name) {
 284                    return true;
 285                }
 286             });
 287             fail("SecurityException should have been thrown");
 288         } catch (final SecurityException e) {
 289             //empty
 290         }
 291     }
 292 
 293     @Test
 294     public void nashornConfigSecurityTest2() {
 295         if (System.getSecurityManager() == null) {
 296             // pass vacuously
 297             return;
 298         }
 299 
 300         final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
 301         try {
 302             fac.getScriptEngine(new String[0], null, new ClassFilter() {
 303                @Override
 304                public boolean exposeToScripts(final String name) {
 305                    return true;
 306                }
 307             });
 308             fail("SecurityException should have been thrown");
 309         } catch (final SecurityException e) {
 310             //empty
 311         }
 312     }
 313 }