[java-plugin-shibd-saml] branch main updated: Stash RelayState when processing LogoutRequests.

Codeberg noreply at shibboleth.net
Mon May 25 20:00:02 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-plugin-shibd-saml.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-saml/commit/36b24f694a042037c38e5f14c6d2f71e1b5de1f3

The following commit(s) were added to refs/heads/main by this push:
     new 36b24f6  Stash RelayState when processing LogoutRequests.
36b24f6 is described below

commit 36b24f694a042037c38e5f14c6d2f71e1b5de1f3
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon May 25 15:59:44 2026 -0400

    Stash RelayState when processing LogoutRequests.
---
 .../flows/saml2/SAML2LogoutConsumerFlowTest.java   | 22 ++++++++++++++--------
 .../saml2/profile/impl/ProcessLogoutRequest.java   | 13 +++++++++----
 .../profile/impl/ProcessLogoutRequestTest.java     |  6 ++++++
 3 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2LogoutConsumerFlowTest.java b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2LogoutConsumerFlowTest.java
index 0f9f1aa..c1a3510 100644
--- a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2LogoutConsumerFlowTest.java
+++ b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2LogoutConsumerFlowTest.java
@@ -27,6 +27,7 @@ import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.SAMLObject;
+import org.opensaml.saml.common.binding.SAMLBindingSupport;
 import org.opensaml.saml.saml2.core.Issuer;
 import org.opensaml.saml.saml2.core.LogoutRequest;
 import org.opensaml.saml.saml2.core.NameID;
@@ -62,6 +63,7 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
 import net.shibboleth.idp.test.PreferFileSystemApplicationContextInitializer;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.codec.Base64Support;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -111,16 +113,19 @@ import net.shibboleth.sp.state.impl.PassthroughStateManager;
 public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
     
     /** Flow ID. */
-    @Nonnull public static final String FLOW_ID = "sp/logout-consumer";
+    @Nonnull @NotEmpty public static final String FLOW_ID = "sp/logout-consumer";
 
     /** Issuer. */
-    @Nonnull public static final String ISSUER = "https://idp.example.org";
+    @Nonnull @NotEmpty public static final String ISSUER = "https://idp.example.org";
 
     /** Audience. */
-    @Nonnull public static final String AUDIENCE = "https://testsp.example.org";
+    @Nonnull @NotEmpty public static final String AUDIENCE = "https://testsp.example.org";
 
     /** ACS URL. */
-    @Nonnull public static final String RESPONSE_URL = "https://sp.example.org/Shibboleth.sso/SAML2/SLO/POST";
+    @Nonnull @NotEmpty public static final String RESPONSE_URL = "https://sp.example.org/Shibboleth.sso/SAML2/SLO/POST";
+    
+    /** Relay state. */
+    @Nonnull @NotEmpty public static final String RELAY_STATE = "dummy";
     
     @Autowired
     @Qualifier("shibboleth.DataSealer")
@@ -239,7 +244,7 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
      */
     @Test
     public void testRequestUnverified() throws IOException {
-        final DDF input = buildRemotedPOSTMessage(buildLogoutRequest(ISSUER + "/bad"), null, null);
+        final DDF input = buildRemotedPOSTMessage(buildLogoutRequest(ISSUER + "/bad"), RELAY_STATE, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         validateError(IdPEventIds.INVALID_PROFILE_CONFIG);
@@ -254,7 +259,7 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
     public void testRequestNoSession() throws Exception {
         final LogoutRequest request = buildLogoutRequest(ISSUER);
         sign(request);
-        final DDF input = buildRemotedPOSTMessage(request, null, null);
+        final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
         setApplicationRequest(APPLICATION_ID, input);
         
         validateLogoutRequestResult(false);
@@ -269,7 +274,7 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
     public void testRequestNoMatch() throws Exception {
         final LogoutRequest request = buildLogoutRequest(ISSUER);
         sign(request);
-        final DDF input = buildRemotedPOSTMessage(request, null, null);
+        final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
         input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
                 "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion'"
                         + "' SPProvidedID='" + ISSUER + "'>jdoe at example.org</NameID>");
@@ -287,7 +292,7 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
     public void testRequestSuccess() throws Exception {
         final LogoutRequest request = buildLogoutRequest(ISSUER);
         sign(request);
-        final DDF input = buildRemotedPOSTMessage(request, null, null);
+        final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
         input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
                 "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' Format='"
                         + NameIDType.EMAIL + "' SPProvidedID='" + ISSUER + "'>jdoe at example.org</NameID>");
@@ -344,6 +349,7 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
         assert issuer != null;
         Assert.assertEquals(stateData.getAuthenticationAuthority(), issuer.getValue());
         Assert.assertEquals(stateData.getRequestID(), request.getID());
+        Assert.assertEquals(stateData.getResource(), SAMLBindingSupport.getRelayState(prc.ensureInboundMessageContext()));
         
         return output;
     }
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequest.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequest.java
index ead2a3b..58fef83 100644
--- a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequest.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequest.java
@@ -30,6 +30,7 @@ import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.binding.SAMLBindingSupport;
 import org.opensaml.saml.saml2.core.Issuer;
 import org.opensaml.saml.saml2.core.LogoutRequest;
 import org.opensaml.saml.saml2.core.NameID;
@@ -225,7 +226,7 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
         final NameID requestedNameID = logoutRequest.getNameID();
         if (requestedNameID == null) {
             log.info("{} No NameID in logout request", getLogPrefix());
-            addToken(issuer, false);
+            addToken(profileRequestContext, issuer, false);
             return;
         }
         
@@ -235,7 +236,7 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
                     : null;
         if (pickled == null) {
             log.info("{} No encoded NameID found in input message", getLogPrefix());
-            addToken(issuer, false);
+            addToken(profileRequestContext, issuer, false);
             return;
         }
                 
@@ -254,7 +255,7 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
 
         final boolean matched = requestMatchesSession(profileRequestContext, issuer, sessionNameID);
         log.debug("{} LogoutRequest {} session from Agent", getLogPrefix(), matched ? "matched" : "did not match");
-        addToken(issuer, matched);
+        addToken(profileRequestContext, issuer, matched);
     }
     
     /**
@@ -336,10 +337,12 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
      * 
      * <p>The token tracks the request ID and the issuer.</p>
      * 
+     * @param profileRequestContext profile request context
      * @param issuer issuer of request
      * @param matched matched signal
      */
-    private void addToken(@Nullable final Issuer issuer, final boolean matched) {
+    private void addToken(@Nonnull final ProfileRequestContext profileRequestContext, @Nullable final Issuer issuer,
+            final boolean matched) {
         
         output.addmember(MATCHED_PARAM).integer(matched ? 1 : 0);
         
@@ -347,6 +350,8 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
         
         state.setRequestID(logoutRequest.getID());
         state.setAuthenticationAuthority(issuer != null ? issuer.getValue() : null);
+        // We have no need for this field's usual purpose so this is a simple way to store off RelayState.
+        state.setResource(SAMLBindingSupport.getRelayState(profileRequestContext.ensureInboundMessageContext()));
         
         try {
             final String token = stateManager.preserveToStateToken(ensureAgent(), ensureApplication(), state);
diff --git a/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java b/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
index e559e66..be836dc 100644
--- a/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
+++ b/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/ProcessLogoutRequestTest.java
@@ -17,11 +17,13 @@ package net.shibboleth.sp.saml.saml2.profile.impl;
 
 import java.io.IOException;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.common.binding.SAMLBindingSupport;
 import org.opensaml.saml.saml2.core.Issuer;
 import org.opensaml.saml.saml2.core.LogoutRequest;
 import org.opensaml.saml.saml2.core.LogoutResponse;
@@ -59,6 +61,8 @@ import net.shibboleth.sp.testing.TestResourceConverter;
 @SuppressWarnings("javadoc")
 public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
 
+    @Nonnull private static final String RELAY_STATE = "dummy";
+    
     private Resource keystoreResource;
     private Resource versionResource;
     private DataSealer sealer;
@@ -311,6 +315,7 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
         final LogoutRequest request = SAML2ActionTestingSupport.buildLogoutRequest(
                 SAML2ActionTestingSupport.buildNameID("jdoe"));
         prc.ensureInboundMessageContext().setMessage(request);
+        SAMLBindingSupport.setRelayState(prc.ensureInboundMessageContext(), RELAY_STATE);
     }
     
     /**
@@ -338,5 +343,6 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
         assert issuer != null;
         Assert.assertEquals(data.getAuthenticationAuthority(), issuer.getValue());
         Assert.assertEquals(data.getRequestID(), request.getID());
+        Assert.assertEquals(data.getResource(), RELAY_STATE);
     }
 }
\ No newline at end of file

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


More information about the commits mailing list