[java-plugin-shibd-saml] 01/02: Fix discontinuity in encoding of opaque session data.
Codeberg
noreply at shibboleth.net
Mon Jun 1 16:53:50 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/126e9c21b50f3aa7a66dab9d4f91c269089d7cc5
commit 126e9c21b50f3aa7a66dab9d4f91c269089d7cc5
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon Jun 1 12:00:25 2026 -0400
Fix discontinuity in encoding of opaque session data.
---
.../flows/saml2/SAML2LogoutConsumerFlowTest.java | 15 +++++----
.../saml2/profile/impl/ProcessLogoutRequest.java | 20 +++++++-----
.../profile/impl/ProcessLogoutRequestTest.java | 36 +++++++++++++---------
3 files changed, 44 insertions(+), 27 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 6259564..d642b82 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
@@ -285,9 +285,10 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
final LogoutRequest request = buildLogoutRequest(ISSUER);
sign(request);
final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='" + ISSUER
+ + "'>jdoe at example.org</NameID>";
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>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
setApplicationRequest(APPLICATION_ID, input);
validateLogoutRequestResult(false);
@@ -302,9 +303,10 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
public void testRequestUnsigned() throws Exception {
final LogoutRequest request = buildLogoutRequest(ISSUER);
final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' Format='"
+ + NameIDType.EMAIL + "' SPProvidedID='" + ISSUER + "'>jdoe at example.org</NameID>";
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>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
setApplicationRequest(APPLICATION_ID, input);
validateError(EventIds.INVALID_MESSAGE);
@@ -320,9 +322,10 @@ public class SAML2LogoutConsumerFlowTest extends AbstractSPFlowTest {
final LogoutRequest request = buildLogoutRequest(ISSUER);
sign(request);
final DDF input = buildRemotedPOSTMessage(request, RELAY_STATE, null);
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' Format='"
+ + NameIDType.EMAIL + "' SPProvidedID='" + ISSUER + "'>jdoe at example.org</NameID>";
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>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
setApplicationRequest(APPLICATION_ID, input);
validateLogoutRequestResult(true);
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 64418df..f8a97c3 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
@@ -14,8 +14,9 @@
package net.shibboleth.sp.saml.saml2.profile.impl;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.io.IOException;
-import java.io.StringReader;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
@@ -57,6 +58,8 @@ import net.shibboleth.saml.saml2.profile.config.navigate.QualifiedNameIDFormatsL
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.DecodingException;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
@@ -256,13 +259,16 @@ public class ProcessLogoutRequest extends AbstractApplicationAction {
// Decode NameID from session data from Agent and unpack the buried information.
NameID sessionNameID = null;
try {
- final XMLObject xmlObject = XMLObjectSupport.unmarshallFromReader(parserPool, new StringReader(pickled));
- if (xmlObject instanceof NameID n) {
- sessionNameID = n;
- } else {
- throw new XMLParserException("Decoded object was of unexpected type.");
+ final byte[] bytes = Base64Support.decodeURLSafe(pickled);
+ try (final InputStream source = new ByteArrayInputStream(bytes)) {
+ final XMLObject xmlObject = XMLObjectSupport.unmarshallFromInputStream(parserPool, source);
+ if (xmlObject instanceof NameID n) {
+ sessionNameID = n;
+ } else {
+ throw new XMLParserException("Decoded object was of unexpected type.");
+ }
}
- } catch (final XMLParserException | UnmarshallingException e) {
+ } catch (final DecodingException | IOException | XMLParserException | UnmarshallingException e) {
log.warn("{} Failed to decode session information", getLogPrefix(), e);
}
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 19c95f5..743d30a 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
@@ -16,6 +16,7 @@ package net.shibboleth.sp.saml.saml2.profile.impl;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.time.Instant;
import javax.annotation.Nonnull;
@@ -48,6 +49,8 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.EncodingException;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.resource.Resource;
import net.shibboleth.shared.security.DataSealer;
@@ -248,10 +251,11 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
}
@Test
- public void testIncompleteSessionData() throws IOException {
+ public void testIncompleteSessionData() throws IOException, EncodingException {
final DDF input = new DDF(null).structure();
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' Format='bar'>foo</NameID>";
input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
- "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' Format='bar'>foo</NameID>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
arc.setInput(input);
final Event event = action.execute(src);
@@ -264,11 +268,12 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
}
@Test
- public void testMatchNoIndex() throws IOException {
+ public void testMatchNoIndex() throws IOException, EncodingException {
final DDF input = new DDF(null).structure();
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
+ + ActionTestingSupport.INBOUND_MSG_ISSUER + "'>jdoe</NameID>";
input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
- "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
- + ActionTestingSupport.INBOUND_MSG_ISSUER + "'>jdoe</NameID>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
arc.setInput(input);
final Event event = action.execute(src);
@@ -281,11 +286,12 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
}
@Test
- public void testNoMatchWithIndex() throws IOException {
+ public void testNoMatchWithIndex() throws IOException, EncodingException {
final DDF input = new DDF(null).structure();
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
+ + ActionTestingSupport.INBOUND_MSG_ISSUER + "!!12345'>jdoe</NameID>";
input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
- "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
- + ActionTestingSupport.INBOUND_MSG_ISSUER + "!!12345'>jdoe</NameID>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
arc.setInput(input);
final SAMLObjectBuilder<SessionIndex> indexBuilder = (SAMLObjectBuilder<SessionIndex>)
@@ -309,11 +315,12 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
}
@Test
- public void testMatchWithIndex() throws IOException {
+ public void testMatchWithIndex() throws IOException, EncodingException {
final DDF input = new DDF(null).structure();
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
+ + ActionTestingSupport.INBOUND_MSG_ISSUER + "!!12345'>jdoe</NameID>";
input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
- "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
- + ActionTestingSupport.INBOUND_MSG_ISSUER + "!!12345'>jdoe</NameID>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
arc.setInput(input);
final SAMLObjectBuilder<SessionIndex> indexBuilder = (SAMLObjectBuilder<SessionIndex>)
@@ -333,11 +340,12 @@ public class ProcessLogoutRequestTest extends BaseApplicationActionTest {
}
@Test
- public void testMatchAsynch() throws IOException {
+ public void testMatchAsynch() throws IOException, EncodingException {
final DDF input = new DDF(null).structure();
+ final String opaque = "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
+ + ActionTestingSupport.INBOUND_MSG_ISSUER + "'>jdoe</NameID>";
input.addmember(ConsumerConstants.SESSION_OPAQUE).addmember(PrepareAgentResponse.NAMEID_PARAM).string(
- "<NameID xmlns='urn:oasis:names:tc:SAML:2.0:assertion' SPProvidedID='"
- + ActionTestingSupport.INBOUND_MSG_ISSUER + "'>jdoe</NameID>");
+ Base64Support.encodeURLSafe(opaque.getBytes(StandardCharsets.UTF_8)));
arc.setInput(input);
final SAMLObjectBuilder<Extensions> extsBuilder = (SAMLObjectBuilder<Extensions>)
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list