keycloak/keycloak

client-policies: editing secure-redirect-uris-enforcer setting in admin ui breaks client policy/profile

Open

#49,252 创建于 2026年5月22日

在 GitHub 查看
 (1 评论) (1 反应) (0 负责人)Java (34,398 star) (8,346 fork)batch import
area/admin/uihelp wantedkind/bugpriority/normalstatus/auto-bumpstatus/auto-expireteam/core-protocolsteam/core-shared

描述

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

admin/ui

Describe the bug

When editing the settings of the secure-redirect-uris-enforcer executor in the admin UI and leaving the Allow permitted domains field empty (to allow all domains), the profile JSON then contains "allow-permitted-domains": [ null ]. When a client is updated for which a client policy with this profile exists, the update fails with:

Client could not be updated: unknown_error

For more on this error consult the server log.

In in the server log an NullPointerException is logged:

[org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-59) Uncaught server error: java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "this.pattern" is null
	at java.base/java.util.regex.Pattern.<init>(Pattern.java:1574)
	at java.base/java.util.regex.Pattern.compile(Pattern.java:1101)
	at java.base/java.util.regex.Pattern.matches(Pattern.java:1220)
	at java.base/java.lang.String.matches(String.java:2958)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor$UriValidation.matchDomain(SecureRedirectUrisEnforcerExecutor.java:501)
	at java.base/java.util.stream.MatchOps$1MatchSink.accept(MatchOps.java:90)
	at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1685)
	at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
	at java.base/java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:632)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor$UriValidation.matchDomains(SecureRedirectUrisEnforcerExecutor.java:505)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor$UriValidation.isValidNormalUri(SecureRedirectUrisEnforcerExecutor.java:474)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor$UriValidation.validate(SecureRedirectUrisEnforcerExecutor.java:286)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor.verifyRedirectUri(SecureRedirectUrisEnforcerExecutor.java:254)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor.verifyRedirectUris(SecureRedirectUrisEnforcerExecutor.java:240)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor.verifyRedirectUris(SecureRedirectUrisEnforcerExecutor.java:211)
	at org.keycloak.services.clientpolicy.executor.SecureRedirectUrisEnforcerExecutor.executeOnEvent(SecureRedirectUrisEnforcerExecutor.java:183)
	at org.keycloak.services.clientpolicy.DefaultClientPolicyManager.lambda$triggerOnEvent$1(DefaultClientPolicyManager.java:59)
	at org.keycloak.services.clientpolicy.DefaultClientPolicyManager.execute(DefaultClientPolicyManager.java:157)
	at org.keycloak.services.clientpolicy.DefaultClientPolicyManager.doPolicyOperation(DefaultClientPolicyManager.java:80)
	at org.keycloak.services.clientpolicy.DefaultClientPolicyManager.triggerOnEvent(DefaultClientPolicyManager.java:57)
	at org.keycloak.services.resources.admin.ClientResource.update(ClientResource.java:159)
	at org.keycloak.services.resources.admin.ClientResource$quarkusrestinvoker$update_ce017e4b2823ce9327deccf447c672318503a2ff.invoke(Unknown Source)
	at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
	at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:190)
	at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:677)
	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
	at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)

Version

26.6.2

Regression

  • The issue is a regression

Expected behavior

The client policy should be evaluated correctly, and an already compliant client should be updated without any errors. If the client is not compliant, a useful error message should be shown.

Actual behavior

In the UI, the user only gets an unknown_error because a NullPointerException happens and cannot update the client, even when it does not violate any client policy.

How to Reproduce?

  1. Create a Client Profile with the secure-redirect-uris-enforcer Executor
  2. Leave the "Allow permitted domains" filed empty in the settings of the Executor e.g.:
  1. Save the profile
  2. The JSON of the Executor show then like:
      {
        "executor": "secure-redirect-uris-enforcer",
        "configuration": {
          "allow-ipv4-loopback-address": "true",
          "allow-ipv6-loopback-address": "true",
          "allow-private-use-uri-scheme": "true",
          "oauth-2-1-compliant": "false",
          "allow-http-scheme": true,
          "allow-wildcard-context-path": false,
          "allow-open-redirect": false,
          "allow-permitted-domains": [
            null
          ]
        }
      }
  1. When the profile is used in a client policy and the policy is evaluated, the null entry in the JSON list leads to a NullPointerException.

Anything else?

The workaround is to edit the JSON of the client profile and remove the null value from the list or remove the allow-permitted-domains property completely from the profile. But every time the executor is edited through the UI, the JSON must be corrected again.

贡献者指南