无法使用 Keycloak 评估基于 Javascript 的策略

Can't evaluate Javascript based policy with Keycloak

我正在尝试测试此项目 https://github.com/mposolda/devconf2019-authz/blob/master/cars-realm.json#L191 中定义的 Java 基于脚本的策略,但每次我尝试访问受保护的资源时,我都会在 keycloak 日志中收到以下错误:

Caused by: java.lang.IllegalStateException: Could not find ScriptEngine for script: Script{id='null', realmId='cars', name='Only From a Specific Client Address', type='text/javascript', code='var contextAttributes = $evaluation.getContext().getAttributes();

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}', description='Defines that only clients from a specific address can do something'}
        at org.keycloak.keycloak-services@15.0.2//org.keycloak.scripting.DefaultScriptingProvider.createPreparedScriptEngine(DefaultScriptingProvider.java:106)
        at org.keycloak.keycloak-services@15.0.2//org.keycloak.scripting.DefaultScriptingProvider.prepareEvaluatableScript(DefaultScriptingProvider.java:72)
        at org.keycloak.keycloak-services@15.0.2//org.keycloak.scripting.DefaultScriptingProvider.prepareEvaluatableScript(DefaultScriptingProvider.java:33)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.js.JSPolicyProviderFactory.lambda$getEvaluatableScript[=11=](JSPolicyProviderFactory.java:109)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.js.ScriptCache.lambda$computeIfAbsent[=11=](ScriptCache.java:80)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1224)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.js.ScriptCache.computeIfAbsent(ScriptCache.java:80)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.js.JSPolicyProviderFactory.getEvaluatableScript(JSPolicyProviderFactory.java:106)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.js.JSPolicyProvider.evaluate(JSPolicyProvider.java:46)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.aggregated.AggregatePolicyProvider.evaluate(AggregatePolicyProvider.java:66)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.aggregated.AggregatePolicyProvider.evaluate(AggregatePolicyProvider.java:66)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.permission.AbstractPermissionProvider.evaluate(AbstractPermissionProvider.java:56)
        at org.keycloak.keycloak-authz-policy-common@15.0.2//org.keycloak.authorization.policy.provider.permission.ScopePolicyProvider.evaluate(ScopePolicyProvider.java:52)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator.lambda$createPolicyEvaluator[=11=](DefaultPolicyEvaluator.java:116)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$PolicyCache.cacheQuery(StoreFactoryCacheSession.java:1098)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$PolicyCache.cacheQuery(StoreFactoryCacheSession.java:1073)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$PolicyCache.findByScopeIds(StoreFactoryCacheSession.java:1045)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.AuthorizationProvider.findByScopeIds(AuthorizationProvider.java:430)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator.evaluate(DefaultPolicyEvaluator.java:86)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.permission.evaluator.UnboundedPermissionEvaluator.lambda$evaluate[=11=](UnboundedPermissionEvaluator.java:49)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.permission.Permissions.lambda$all(Permissions.java:87)
        at java.base/java.util.function.Consumer.lambda$andThen[=11=](Consumer.java:65)
        at java.base/java.util.function.Consumer.lambda$andThen[=11=](Consumer.java:65)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.accept(StoreFactoryCacheSession.java:678)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.accept(StoreFactoryCacheSession.java:673)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
        at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
        at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
        at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.utils.ClosingStream.forEach(ClosingStream.java:128)
        at org.keycloak.keycloak-model-jpa@15.0.2//org.keycloak.authorization.jpa.store.JPAResourceStore.findByOwnerFilter(JPAResourceStore.java:136)
        at org.keycloak.keycloak-model-jpa@15.0.2//org.keycloak.authorization.jpa.store.JPAResourceStore.findByOwner(JPAResourceStore.java:101)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.lambda$findByOwner(StoreFactoryCacheSession.java:673)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.cacheQuery(StoreFactoryCacheSession.java:845)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.cacheQuery(StoreFactoryCacheSession.java:830)
        at org.keycloak.keycloak-model-infinispan@15.0.2//org.keycloak.models.cache.infinispan.authorization.StoreFactoryCacheSession$ResourceCache.findByOwner(StoreFactoryCacheSession.java:671)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.AuthorizationProvider.findByOwner(AuthorizationProvider.java:501)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.permission.Permissions.all(Permissions.java:85)
        at org.keycloak.keycloak-server-spi-private@15.0.2//org.keycloak.authorization.permission.evaluator.UnboundedPermissionEvaluator.evaluate(UnboundedPermissionEvaluator.java:48)

为了使这个示例有效,我还需要执行任何进一步的步骤吗?

密钥斗篷版本:15.0.2 Java 版本:15

谢谢!

当我们查看日志消息的第一行时:

Could not find ScriptEngine for script: Script{ ... type='text/javascript'... }

我们看到 keycloak 无法加载 javascript 脚本引擎。

因为 Java >= 15,JVM 没有提供 javascript 引擎(参见 JEP 372)。这就是 keycloak 找不到 javascript 引擎的原因。

我看到了两个可能的问题解决方案:

  • 通过一些第 3 方库提供 javascript 引擎(详情请参阅 by Paul Taylor),或
  • 将 Java 降级到 <= 14(不推荐)。