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  * @test
  43  * @run testng/othervm jdk.nashorn.api.scripting.test.ScriptEngineSecurityTest
  44  */
  45 @SuppressWarnings("javadoc")
  46 public 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")
 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 }