Skip to content

Commit

Permalink
Control access to Java.type via a property
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaroslav Tulach committed May 28, 2019
1 parent f47f36c commit f21511c
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Predicate;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
Expand Down Expand Up @@ -125,7 +126,10 @@ private ScriptEngine postConfigure(ScriptEngine eng) {
}
if (eng.getFactory().getNames().contains("Graal.js")) { // NOI18N
final Bindings b = eng.getBindings(ScriptContext.ENGINE_SCOPE);
b.put("polyglot.js.allowHostAccess", true); // NOI18N
b.put("polyglot.js.nashorn-compat", true); // NOI18N
b.put("polyglot.js.allowHostClassLookup", (Predicate<String>) (s) -> { // NOI18N
return allowHostClassLookup(eng, s);
});
}
if (isNashornFactory(eng.getFactory())) {
return secureEngineEngine(eng);
Expand All @@ -138,7 +142,7 @@ private ScriptEngine postConfigure(ScriptEngine eng) {
static {
Class<?> klass;
try {
klass = Class.forName("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
klass = Class.forName("jdk.nashorn.api.scripting.NashornScriptEngineFactory"); // NOI18N
} catch (ClassNotFoundException ex) {
klass = String.class;
}
Expand All @@ -148,22 +152,32 @@ private boolean isNashornFactory(ScriptEngineFactory f) {
return nashornScriptEngineFactory.isInstance(f);
}

private ScriptEngine secureEngineEngine(ScriptEngine e) {
private ScriptEngine secureEngineEngine(ScriptEngine prototypeEngine) {
final ScriptEngine[] engine = { prototypeEngine };
try {
ScriptEngineFactory f = e.getFactory();
ScriptEngineFactory f = engine[0].getFactory();
final Class<? extends ScriptEngineFactory> factoryClass = f.getClass();
final ClassLoader factoryClassLoader = factoryClass.getClassLoader();
Class<?> filterClass = Class.forName("jdk.nashorn.api.scripting.ClassFilter", true, factoryClassLoader);
Method createMethod = factoryClass.getMethod("getScriptEngine", filterClass);
Object filter = java.lang.reflect.Proxy.newProxyInstance(factoryClassLoader, new Class[]{filterClass}, (Object proxy, Method method, Object[] args) -> {
return false;
return allowHostClassLookup(engine[0], (String) args[0]);
});
return (ScriptEngine) createMethod.invoke(f, filter);
engine[0] = (ScriptEngine) createMethod.invoke(f, filter);
return engine[0];
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
return e;
return engine[0];
}
}

private boolean allowHostClassLookup(final ScriptEngine engine, String className) {
Object engineAllAccess = engine.getBindings(ScriptContext.ENGINE_SCOPE).get("allowAllAccess");
Object globalAllAccess = getBindings().get("allowAllAccess");

boolean allowClassAccess = Boolean.TRUE.equals(engineAllAccess) || Boolean.TRUE.equals(globalAllAccess);
return allowClassAccess;
}

private final class GraalJSWrapperFactory implements ScriptEngineFactory {
private final ScriptEngineFactory original;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
import java.util.List;
import java.util.Map;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -228,6 +230,37 @@ public void returnArrayInJS() throws Exception {
assertEquals(sum, list.get("4"));
}

@Test
public void allowLoadAClassInJS() throws Exception {
engine.getBindings(ScriptContext.ENGINE_SCOPE).put("allowAllAccess", true); // NOI18N
Object fn = engine.eval("(function(obj) {\n"
+ " var Long = Java.type('java.lang.Long');\n"
+ " return new Long(33);\n"
+ "})\n");
assertNotNull(fn);

Object value = ((Invocable) engine).invokeMethod(fn, "call", null, null);
assertTrue("Is number: " + value, value instanceof Number);
assertEquals(33, ((Number) value).intValue());
}

@Test
public void preventLoadAClassInJS() throws Exception {
Object fn = engine.eval("(function(obj) {\n"
+ " var Long = Java.type('java.lang.Long');\n"
+ " return new Long(33);\n"
+ "})\n");
assertNotNull(fn);

Object value;
try {
value = ((Invocable) engine).invokeMethod(fn, "call", null, null);
} catch (ScriptException | RuntimeException ex) {
return;
}
fail("Access to Java.type classes shall be prevented: " + value);
}

public static interface ArrayLike {
int length();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ private void init(Snapshot snapshot) throws RuntimeException {
try {
ScriptEngineManager manager = Scripting.createManager();
engine = manager.getEngineByName("JavaScript"); // NOI18N
engine.getBindings(ScriptContext.ENGINE_SCOPE).put("polyglot.js.nashorn-compat", true);
engine.getBindings(ScriptContext.ENGINE_SCOPE).put("allowAllAccess", true);
InputStream strm = getInitStream();
CompiledScript cs = ((Compilable)engine).compile(new InputStreamReader(strm));
cs.eval();
Expand Down

0 comments on commit f21511c

Please sign in to comment.