JS policy should use ScriptingSPI

This commit is contained in:
Pedro Igor 2017-06-16 11:49:32 -03:00
parent 93105a2182
commit 0b5e6b0d49
3 changed files with 36 additions and 24 deletions

View file

@ -17,37 +17,27 @@
*/ */
package org.keycloak.authorization.policy.provider.js; package org.keycloak.authorization.policy.provider.js;
import java.util.function.Supplier; import org.keycloak.authorization.AuthorizationProvider;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation; import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider; import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.ScriptModel;
import org.keycloak.scripting.InvocableScriptAdapter;
import org.keycloak.scripting.ScriptingProvider;
/** /**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a> * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/ */
public class JSPolicyProvider implements PolicyProvider { public class JSPolicyProvider implements PolicyProvider {
private Supplier<ScriptEngine> engineProvider;
public JSPolicyProvider(Supplier<ScriptEngine> engineProvider) {
this.engineProvider = engineProvider;
}
@Override @Override
public void evaluate(Evaluation evaluation) { public void evaluate(Evaluation evaluation) {
ScriptEngine engine = engineProvider.get();
engine.put("$evaluation", evaluation);
Policy policy = evaluation.getPolicy(); Policy policy = evaluation.getPolicy();
try { try {
engine.eval(policy.getConfig().get("code")); getInvocableScriptAdapter(policy, evaluation).eval();
} catch (ScriptException e) { } catch (Exception e) {
throw new RuntimeException("Error evaluating JS Policy [" + policy.getName() + "].", e); throw new RuntimeException("Error evaluating JS Policy [" + policy.getName() + "].", e);
} }
} }
@ -56,4 +46,24 @@ public class JSPolicyProvider implements PolicyProvider {
public void close() { public void close() {
} }
private InvocableScriptAdapter getInvocableScriptAdapter(Policy policy, Evaluation evaluation) {
String scriptName = policy.getName();
String scriptCode = policy.getConfig().get("code");
String scriptDescription = policy.getDescription();
AuthorizationProvider authorization = evaluation.getAuthorizationProvider();
RealmModel realm = authorization.getRealm();
ScriptingProvider scripting = authorization.getKeycloakSession().getProvider(ScriptingProvider.class);
//TODO lookup script by scriptId instead of creating it every time
ScriptModel script = scripting.createScript(realm.getId(), ScriptModel.TEXT_JAVASCRIPT, scriptName, scriptCode, scriptDescription);
//how to deal with long running scripts -> timeout?
return scripting.prepareInvocableScript(script, bindings -> {
bindings.put("script", script);
bindings.put("$evaluation", evaluation);
});
}
} }

View file

@ -1,9 +1,5 @@
package org.keycloak.authorization.policy.provider.js; package org.keycloak.authorization.policy.provider.js;
import java.util.Map;
import javax.script.ScriptEngineManager;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy; import org.keycloak.authorization.model.Policy;
@ -19,9 +15,7 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
*/ */
public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRepresentation> { public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRepresentation> {
private static final String ENGINE = "nashorn"; private JSPolicyProvider provider = new JSPolicyProvider();
private JSPolicyProvider provider = new JSPolicyProvider(() -> new ScriptEngineManager().getEngineByName(ENGINE));
@Override @Override
public String getName() { public String getName() {

View file

@ -78,6 +78,14 @@ public class InvocableScriptAdapter implements Invocable {
} }
} }
public Object eval() throws ScriptExecutionException {
try {
return scriptEngine.eval(scriptModel.getCode());
} catch (ScriptException e) {
throw new ScriptExecutionException(scriptModel, e);
}
}
@Override @Override
public <T> T getInterface(Class<T> clazz) { public <T> T getInterface(Class<T> clazz) {
return getInvocableEngine().getInterface(clazz); return getInvocableEngine().getInterface(clazz);