[java-plugin-shibd-saml] branch main updated: Add RelayState to SAML initiator and tests.
Scott Cantor
cantor.2 at osu.edu
Wed Aug 21 16:08:36 UTC 2024
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-plugin-shibd-saml.
View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd-saml.git;a=commit;h=b4e2e83baf4b8c24e45365581b448be57b565092
The following commit(s) were added to refs/heads/main by this push:
new b4e2e83 Add RelayState to SAML initiator and tests.
b4e2e83 is described below
commit b4e2e83baf4b8c24e45365581b448be57b565092
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 21 12:08:33 2024 -0400
Add RelayState to SAML initiator and tests.
---
.../flows/saml2/SAML2SessionInitiatorFlowTest.java | 99 +++++++++++++++++++++-
.../saml/saml2/profile/impl/AddAuthnRequest.java | 7 ++
2 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2SessionInitiatorFlowTest.java b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2SessionInitiatorFlowTest.java
index 06ae546..fdf59ff 100644
--- a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2SessionInitiatorFlowTest.java
+++ b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2SessionInitiatorFlowTest.java
@@ -16,13 +16,17 @@ package net.shibboleth.sp.saml.flows.saml2;
import java.io.IOException;
import java.time.Instant;
+import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.SAMLObject;
+import org.opensaml.saml.common.binding.SAMLBindingSupport;
+import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder;
import org.opensaml.saml.saml2.core.AuthnContext;
import org.opensaml.saml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
@@ -31,6 +35,7 @@ import org.opensaml.saml.saml2.core.NameIDPolicy;
import org.opensaml.saml.saml2.core.NameIDType;
import org.opensaml.saml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml.saml2.metadata.NameIDFormat;
+import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.webflow.executor.FlowExecutionResult;
@@ -38,9 +43,14 @@ import org.testng.Assert;
import org.testng.annotations.Test;
import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.net.URISupport;
+import net.shibboleth.shared.primitive.NonnullSupplier;
import net.shibboleth.sp.context.AgentRequestContext;
import net.shibboleth.sp.ddf.DDF;
import net.shibboleth.sp.flows.AbstractSPFlowTest;
+import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
import net.shibboleth.sp.profile.InitiatorConstants;
/**
@@ -141,17 +151,18 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
}
/**
- * Test simple success case.
+ * Test simple success case with preset relay state.
*
* @throws IOException
* @throws MessageDecodingException
*/
@Test
- public void testSimple() throws IOException, MessageDecodingException {
+ public void testSimpleWithState() throws IOException, MessageDecodingException {
setDefaultAuth();
final DDF input = new DDF(null).structure();
input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+ input.addmember(InitiatorConstants.STATE).string("foostate");
setApplicationRequest(APPLICATION_ID, input);
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -166,7 +177,37 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
assertFalse(req.isForceAuthn());
assertFalse(req.isPassive());
}
-
+
+ /**
+ * Test simple success case with computed relay state.
+ *
+ * @throws IOException
+ * @throws MessageDecodingException
+ */
+ @Test
+ public void testSimpleWithoutState() throws IOException, MessageDecodingException {
+ setDefaultAuth();
+
+ final DDF input = new DDF(null).structure();
+ input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+ final DDF httpreq = input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME);
+ httpreq.addmember(RemotedHttpServletRequest.REQUEST_URL).unsafe_string("https://sp.example.org/cgi-bin/test.cgi".getBytes());
+ httpreq.addmember(RemotedHttpServletRequest.QUERY_STRING).unsafe_string("foo=bar%20baz&frobnitz=zorkmid".getBytes());
+ setApplicationRequest(APPLICATION_ID, input);
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertFlowExecutionResult(result, FLOW_ID);
+ assertFlowExecutionOutcome(result.getOutcome());
+
+ assertOutputMessageEvent(result, null);
+ final AuthnRequest req = validateOutputMessage(result, null);
+ Assert.assertNull(req.getSubject());
+ Assert.assertNull(req.getRequestedAuthnContext());
+ Assert.assertNull(req.getScoping());
+ assertFalse(req.isForceAuthn());
+ assertFalse(req.isPassive());
+ }
+
/**
* Test success supplying ForceAuthn from agent.
*
@@ -389,6 +430,7 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
final ProfileRequestContext prc = retrieveProfileRequestContext(result);
assert prc != null;
final AgentRequestContext arc = prc.ensureSubcontext(AgentRequestContext.class);
+ final DDF input = arc.getInput();
final DDF output = arc.getOutput();
assert output != null;
@@ -399,7 +441,7 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
final AuthnRequest authnRequest;
final String redirect = http.getmember("redirect").string();
if (redirect != null) {
- final SAMLObject saml = decodeRedirect(redirect);
+ final SAMLObject saml = decodeRedirect(redirect, input != null ? input.getmember(InitiatorConstants.STATE).string() : null);
assert saml instanceof AuthnRequest;
authnRequest = (AuthnRequest) saml;
Assert.assertTrue(redirect.startsWith(authnRequest.getDestination()));
@@ -410,6 +452,8 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
final Object saml = prc.ensureOutboundMessageContext().ensureMessage();
assert saml instanceof AuthnRequest;
authnRequest = (AuthnRequest) saml;
+ Assert.assertEquals(SAMLBindingSupport.getRelayState(prc.ensureOutboundMessageContext()),
+ input != null ? input.getmember(InitiatorConstants.STATE).string() : null);
}
assert authnRequest != null;
@@ -425,5 +469,52 @@ public class SAML2SessionInitiatorFlowTest extends AbstractSPFlowTest {
return authnRequest;
}
+
+ /**
+ * Decodes a SAML message encoded via HTTP-Redirect binding.
+ *
+ * @param url the encoded redirect
+ * @param relayState RelayState to check for
+ *
+ * @return decoded message
+ * @throws MessageDecodingException
+ */
+ @Nonnull protected SAMLObject decodeRedirect(@Nullable final String url, @Nullable final String relayState)
+ throws MessageDecodingException {
+ final MockHttpServletRequest mock = new MockHttpServletRequest("GET", url);
+ final int index = url != null ? url.indexOf('?') : -1;
+ if (url == null || index < 0) {
+ throw new MessageDecodingException("No query string");
+ }
+ final List<Pair<String,String>> params = URISupport.parseQueryString(url.substring(index + 1));
+ for (final var param : params) {
+ final String name = param.getFirst();
+ if (name != null) {
+ mock.addParameter(name, param.getSecond());
+ }
+ }
+
+ final HTTPRedirectDeflateDecoder decoder = new HTTPRedirectDeflateDecoder();
+ decoder.setHttpServletRequestSupplier(NonnullSupplier.of(mock));
+ decoder.setParserPool(parserPool);
+
+ try {
+ decoder.initialize();
+ } catch (final ComponentInitializationException e) {
+ throw new MessageDecodingException(e);
+ }
+
+ decoder.decode();
+
+ final MessageContext mc = decoder.getMessageContext();
+ decoder.destroy();
+
+ if (mc != null && mc.getMessage() instanceof SAMLObject saml) {
+ Assert.assertEquals(SAMLBindingSupport.getRelayState(mc), relayState);
+ return saml;
+ }
+ throw new MessageDecodingException("No message, or incorrect type.");
+ }
+
}
\ No newline at end of file
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/AddAuthnRequest.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/AddAuthnRequest.java
index ef5ad74..2951bb6 100644
--- a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/AddAuthnRequest.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/AddAuthnRequest.java
@@ -47,6 +47,7 @@ import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.common.SAMLVersion;
+import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.ext.reqattr.RequestedAttributes;
import org.opensaml.saml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
@@ -309,6 +310,12 @@ public class AddAuthnRequest extends AbstractApplicationAction {
profileRequestContext.ensureOutboundMessageContext().setMessage(object);
+ // Check for RelayState.
+ final String relayState = input.getmember(InitiatorConstants.STATE).string();
+ if (relayState != null) {
+ SAMLBindingSupport.setRelayState(profileRequestContext.ensureOutboundMessageContext(), relayState);
+ }
+
log.info("{} Generated AuthnRequest with ID {} from {}", getLogPrefix(), object.getID(), issuerId);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list