Cache compiled scripts in JSPolicyProviderFactory
This commit is contained in:
parent
7614ff8c6f
commit
a04d79c576
2 changed files with 44 additions and 26 deletions
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue