Cache compiled scripts in JSPolicyProviderFactory

This commit is contained in:
Jay Anslow 2017-06-19 16:53:07 +01:00
parent 7614ff8c6f
commit a04d79c576
2 changed files with 44 additions and 26 deletions

View file

@ -17,27 +17,30 @@
*/ */
package org.keycloak.authorization.policy.provider.js; package org.keycloak.authorization.policy.provider.js;
import java.util.function.BiFunction;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
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.EvaluatableScriptAdapter; import org.keycloak.scripting.EvaluatableScriptAdapter;
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 { class JSPolicyProvider implements PolicyProvider {
private final BiFunction<AuthorizationProvider, Policy, EvaluatableScriptAdapter> evaluatableScript;
JSPolicyProvider(final BiFunction<AuthorizationProvider, Policy, EvaluatableScriptAdapter> evaluatableScript) {
this.evaluatableScript = evaluatableScript;
}
@Override @Override
public void evaluate(Evaluation evaluation) { public void evaluate(Evaluation evaluation) {
Policy policy = evaluation.getPolicy(); Policy policy = evaluation.getPolicy();
AuthorizationProvider authorization = evaluation.getAuthorizationProvider(); AuthorizationProvider authorization = evaluation.getAuthorizationProvider();
ScriptModel script = getScriptModel(policy, authorization); final EvaluatableScriptAdapter adapter = evaluatableScript.apply(authorization, policy);
final EvaluatableScriptAdapter adapter = getScriptingProvider(authorization).prepareEvaluatableScript(script);
try { try {
//how to deal with long running scripts -> timeout? //how to deal with long running scripts -> timeout?
@ -53,21 +56,5 @@ public class JSPolicyProvider implements PolicyProvider {
@Override @Override
public void close() { public void close() {
}
private ScriptModel getScriptModel(final Policy policy, final AuthorizationProvider authorization) {
String scriptName = policy.getName();
String scriptCode = policy.getConfig().get("code");
String scriptDescription = policy.getDescription();
RealmModel realm = authorization.getRealm();
//TODO lookup script by scriptId instead of creating it every time
return getScriptingProvider(authorization).createScript(realm.getId(), ScriptModel.TEXT_JAVASCRIPT, scriptName, scriptCode, scriptDescription);
}
private ScriptingProvider getScriptingProvider(final AuthorizationProvider authorization) {
return authorization.getKeycloakSession().getProvider(ScriptingProvider.class);
} }
} }

View file

@ -1,5 +1,9 @@
package org.keycloak.authorization.policy.provider.js; package org.keycloak.authorization.policy.provider.js;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
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;
@ -7,15 +11,20 @@ import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory; import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.ScriptModel;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation; import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.scripting.EvaluatableScriptAdapter;
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 JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRepresentation> { public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRepresentation> {
private JSPolicyProvider provider = new JSPolicyProvider(); private final JSPolicyProvider provider = new JSPolicyProvider(this::getEvaluatableScript);
private final Map<String, EvaluatableScriptAdapter> scripts = Collections.synchronizedMap(new HashMap<>());
@Override @Override
public String getName() { public String getName() {
@ -63,8 +72,9 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRe
updatePolicy(policy, representation.getConfig().get("code")); updatePolicy(policy, representation.getConfig().get("code"));
} }
private void updatePolicy(Policy policy, String code) { @Override
policy.putConfig("code", code); public void onRemove(final Policy policy, final AuthorizationProvider authorization) {
scripts.remove(policy.getId());
} }
@Override @Override
@ -86,4 +96,25 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory<JSPolicyRe
public String getId() { public String getId() {
return "js"; return "js";
} }
private EvaluatableScriptAdapter getEvaluatableScript(final AuthorizationProvider authz, final Policy policy) {
return scripts.computeIfAbsent(policy.getId(), id -> {
final ScriptingProvider scripting = authz.getKeycloakSession().getProvider(ScriptingProvider.class);
ScriptModel script = getScriptModel(policy, authz.getRealm(), scripting);
return scripting.prepareEvaluatableScript(script);
});
}
private ScriptModel getScriptModel(final Policy policy, final RealmModel realm, final ScriptingProvider scripting) {
String scriptName = policy.getName();
String scriptCode = policy.getConfig().get("code");
String scriptDescription = policy.getDescription();
//TODO lookup script by scriptId instead of creating it every time
return scripting.createScript(realm.getId(), ScriptModel.TEXT_JAVASCRIPT, scriptName, scriptCode, scriptDescription);
}
private void updatePolicy(Policy policy, String code) {
policy.putConfig("code", code);
}
} }