[java-idp-oidc] branch main updated: JOIDC-250 - customRedirectUriValidationStrategy for OIDC.Logout

Codeberg noreply at shibboleth.net
Wed Jun 24 09:30:15 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository java-idp-oidc.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-oidc/commit/a248d6be6aea8e2cc94977552f041c5508432b81

The following commit(s) were added to refs/heads/main by this push:
     new a248d6be JOIDC-250 - customRedirectUriValidationStrategy for OIDC.Logout
a248d6be is described below

commit a248d6be6aea8e2cc94977552f041c5508432b81
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Jun 24 12:23:57 2026 +0300

    JOIDC-250 - customRedirectUriValidationStrategy for OIDC.Logout
    
    https://shibboleth.atlassian.net/browse/JOIDC-250
    
    Exploit the new OIDC.Logout option 'customPostLogoutRedirectUriValidationStrategy'.
---
 .../impl/ValidatePostLogoutRedirectURI.java        | 40 +++++++++++++++++++++-
 .../impl/ValidatePostLogoutRedirectURITest.java    | 40 +++++++++++++++++++++-
 2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURI.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURI.java
index 59ecb3fe..a522f5f5 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURI.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURI.java
@@ -16,6 +16,7 @@ package net.shibboleth.idp.plugin.oidc.op.logout.profile.impl;
 
 import java.net.URI;
 import java.util.function.BiPredicate;
+import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -26,12 +27,13 @@ import org.slf4j.Logger;
 
 import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCRpInitiatedLogoutContext;
 import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultPostLogoutRedirectURIValidationPredicate;
+import net.shibboleth.oidc.profile.config.navigate.CustomPostLogoutRedirectUriValidationStrategyLookupFunction;
 import net.shibboleth.oidc.profile.core.OidcEventIds;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
- * Action that validates post redirect URI is expected if it's being requested.
+ * Action that validates post logout redirect URI is expected if it's being requested.
  */
 public class ValidatePostLogoutRedirectURI extends AbstractOIDCRpInitiatedLogoutAction {
 
@@ -41,6 +43,10 @@ public class ValidatePostLogoutRedirectURI extends AbstractOIDCRpInitiatedLogout
     /** Strategy used to validate the post logout redirect URIs. */
     @Nonnull private BiPredicate<ProfileRequestContext, URI> redirectURIValidationStrategy;
 
+    /** Strategy to obtain custom post logout redirect URI validation strategy. */
+    @Nonnull private Function<ProfileRequestContext,BiPredicate<URI, ProfileRequestContext>>
+        customPostLogoutRedirectUriValidationStrategyLookupStrategy;
+
     /** The redirect URI to be validated. */
     @Nullable private URI requestedRedirectURI;
 
@@ -49,6 +55,8 @@ public class ValidatePostLogoutRedirectURI extends AbstractOIDCRpInitiatedLogout
      */
     public ValidatePostLogoutRedirectURI() {
         redirectURIValidationStrategy = new DefaultPostLogoutRedirectURIValidationPredicate();
+        customPostLogoutRedirectUriValidationStrategyLookupStrategy =
+                new CustomPostLogoutRedirectUriValidationStrategyLookupFunction();
     }
 
     /**
@@ -62,6 +70,22 @@ public class ValidatePostLogoutRedirectURI extends AbstractOIDCRpInitiatedLogout
                 Constraint.isNotNull(strategy, "RedirectURILookupStrategy lookup strategy cannot be null");
     }
 
+    /**
+     * Set the strategy to obtain custom post logout redirect URI validation strategy. If a non-null value is resolved
+     * via strategy, the bi-predicate will be used for validating the incoming request URI value.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 4.4.0
+     */
+    public void setCustomPostLogoutRedirectUriValidationStrategyLookupStrategy(@Nonnull
+            final Function<ProfileRequestContext,BiPredicate<URI, ProfileRequestContext>> strategy) {
+        checkSetterPreconditions();
+
+        customPostLogoutRedirectUriValidationStrategyLookupStrategy = Constraint.isNotNull(strategy,
+                "Custom post logout redirect URI validation lookup strategy cannot be null");
+    }
+
     /** {@inheritDoc} */
     @Override
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
@@ -84,6 +108,20 @@ public class ValidatePostLogoutRedirectURI extends AbstractOIDCRpInitiatedLogout
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        final BiPredicate<URI, ProfileRequestContext> customPostLogoutRedirectUriValidationStrategy =
+                customPostLogoutRedirectUriValidationStrategyLookupStrategy.apply(profileRequestContext);
+        if (customPostLogoutRedirectUriValidationStrategy != null) {
+            if (!customPostLogoutRedirectUriValidationStrategy.test(requestedRedirectURI, profileRequestContext)) {
+                log.warn("{} Custom post logout redirect URI validation failed for {}", getLogPrefix(),
+                        requestedRedirectURI);
+                ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REDIRECT_URI);
+            } else {
+                log.debug("{} Custom post logout redirect URI validation successful for {}", getLogPrefix(),
+                        requestedRedirectURI);
+            }
+            return;
+        }
+
         if (!redirectURIValidationStrategy.test(profileRequestContext, requestedRedirectURI)) {
             log.warn("{} Post logout redirection URI {} did not pass the validation", getLogPrefix(),
                     requestedRedirectURI);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURITest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURITest.java
index 530d3e47..bf1fd2e3 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURITest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/logout/profile/impl/ValidatePostLogoutRedirectURITest.java
@@ -17,7 +17,10 @@ package net.shibboleth.idp.plugin.oidc.op.logout.profile.impl;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
 
+import org.opensaml.profile.context.ProfileRequestContext;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -37,7 +40,15 @@ public class ValidatePostLogoutRedirectURITest
 
     @Override
     protected ValidatePostLogoutRedirectURI constructAction() {
+        return constructAction(null);
+    }
+
+    protected ValidatePostLogoutRedirectURI constructAction(
+            final Function<ProfileRequestContext,BiPredicate<URI, ProfileRequestContext>> customStrategy) {
         final ValidatePostLogoutRedirectURI action = new ValidatePostLogoutRedirectURI();
+        if (customStrategy != null) {
+            action.setCustomPostLogoutRedirectUriValidationStrategyLookupStrategy(customStrategy);
+        }
         try {
             action.initialize();
         } catch (final ComponentInitializationException e) {
@@ -45,7 +56,7 @@ public class ValidatePostLogoutRedirectURITest
         }
         return action;
     }
-    
+
     @Test
     public void noRequestedPostLogoutRedirectURis() {
         ActionTestingSupport.assertProceedEvent(action.execute(requestContext));
@@ -57,6 +68,13 @@ public class ValidatePostLogoutRedirectURITest
         ActionTestingSupport.assertEvent(action.execute(requestContext), OidcEventIds.INVALID_REDIRECT_URI);
     }
 
+    @Test
+    public void noRegisteredPostLogoutRedirectURis_overrideWithCustomPredicate() {
+        action = constructAction(p -> ((prc, uri) -> true));
+        rpInitiatedLogoutContext.setPostLogoutRedirectUri(mockPostLogoutRedirectUri());
+        ActionTestingSupport.assertProceedEvent(action.execute(requestContext));
+    }
+
     @Test
     public void noMatchingRegisteredPostLogoutRedirectURis() throws URISyntaxException {
         final OIDCClientMetadata metadata = new OIDCClientMetadata();
@@ -66,6 +84,16 @@ public class ValidatePostLogoutRedirectURITest
         ActionTestingSupport.assertEvent(action.execute(requestContext), OidcEventIds.INVALID_REDIRECT_URI);
     }
 
+    @Test
+    public void noMatchingRegisteredPostLogoutRedirectURis_overrideWithCustomPredicate() throws URISyntaxException {
+        action = constructAction(p -> ((prc, uri) -> true));
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setPostLogoutRedirectionURIs(Set.of(new URI("https://rp.example.com/notMatching")));
+        oidcMetadataContext.setClientInformation(new OIDCClientInformation(new ClientID("mockClientId"), metadata));
+        rpInitiatedLogoutContext.setPostLogoutRedirectUri(mockPostLogoutRedirectUri());
+        ActionTestingSupport.assertProceedEvent(action.execute(requestContext));
+    }
+
     @Test
     public void matchingRegisteredPostLogoutRedirectURis() {
         final OIDCClientMetadata metadata = new OIDCClientMetadata();
@@ -75,6 +103,16 @@ public class ValidatePostLogoutRedirectURITest
         ActionTestingSupport.assertProceedEvent(action.execute(requestContext));
     }
 
+    @Test
+    public void matchingRegisteredPostLogoutRedirectURis_overrideWithCustomPredicate() {
+        action = constructAction(p -> ((prc, uri) -> false));
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setPostLogoutRedirectionURIs(Set.of(mockPostLogoutRedirectUri()));
+        oidcMetadataContext.setClientInformation(new OIDCClientInformation(new ClientID("mockClientId"), metadata));
+        rpInitiatedLogoutContext.setPostLogoutRedirectUri(mockPostLogoutRedirectUri());
+        ActionTestingSupport.assertEvent(action.execute(requestContext), OidcEventIds.INVALID_REDIRECT_URI);
+    }
+
     protected URI mockPostLogoutRedirectUri() {
         try {
             return new URI("https://rp.example.com/postLogout");

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list