[automation] Create Nashorn script engines with the proper class loader (#1799)

This should fix the issue reported here:
https://community.openhab.org/t/openhab-3-0-milestone-2-discussion/107564/8

where the Nashorn script engine would be created with the
current thread's class loader, causing JS code like this:
```
var Log = Java.type("org.openhab.core.model.script.actions.Log");
Log.logError("Experiments", "This is an OH error log");
Log.logWarn("Experiments", "This is an OH warn log");
Log.logInfo("Experiments", "This is an OH info log");
Log.logDebug("Experiments", "This is an OH debug log");
```
to run fine when the rule was triggered but fail to find the Log
class when run from the REST API's `/rest/rules/{ruleUID}/runnow`,
because in that case the generic createScriptEngine implementation
would return script engines using the JAX-RS class loader as the
"app" class loader.

Note:
We also have an opportunity to restrict which classes are exposed
to the script with a ClassFilter to a specific set:
https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornScriptEngineFactory.html#getScriptEngine-java.lang.String:A-java.lang.ClassLoader-jdk.nashorn.api.scripting.ClassFilter-
This could prove useful to mitigate code execution vulnerabilities,
as the script code is modifiable remotely.

Signed-off-by: Yannick Schaus <github@schaus.net>
pull/1821/head
Yannick Schaus 2020-11-14 15:17:33 +01:00 committed by GitHub
parent 7cb746ece1
commit 4e045204ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 11 additions and 0 deletions

View File

@ -24,6 +24,7 @@ import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.module.script.AbstractScriptEngineFactory;
import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.osgi.service.component.annotations.Component;
@ -33,6 +34,7 @@ import org.osgi.service.component.annotations.Component;
*
* @author Simon Merschjohann - Initial contribution
* @author Scott Rushworth - removed default methods provided by ScriptEngineFactory
* @author Yannick Schaus - create script engines with the bundle's class loader as "app" class loader
*/
@NonNullByDefault
@Component(service = ScriptEngineFactory.class)
@ -72,4 +74,13 @@ public class NashornScriptEngineFactory extends AbstractScriptEngineFactory {
logger.error("ScriptException while importing scope: {}", ex.getMessage());
}
}
@Override
public @Nullable ScriptEngine createScriptEngine(String scriptType) {
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(NashornScriptEngineFactory.class.getClassLoader());
ScriptEngine scriptEngine = super.createScriptEngine(scriptType);
Thread.currentThread().setContextClassLoader(originalClassLoader);
return scriptEngine;
}
}