[java-plugin-shibd-saml] branch main updated: Fix message handler access to servlet request and add tests.

Scott Cantor cantor.2 at osu.edu
Thu Oct 3 16:20:40 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=9b66aa3a8ee6071078e6c7beb654ec8f4a776c57

The following commit(s) were added to refs/heads/main by this push:
     new 9b66aa3  Fix message handler access to servlet request and add tests.
9b66aa3 is described below

commit 9b66aa3a8ee6071078e6c7beb654ec8f4a776c57
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Oct 3 12:20:37 2024 -0400

    Fix message handler access to servlet request and add tests.
---
 .../idp/flows/sp/consumer/saml2/saml2-beans.xml    |   3 +-
 .../flows/saml2/SAML2TokenConsumerFlowTest.java    | 115 +++++++++++++++++++--
 2 files changed, 111 insertions(+), 7 deletions(-)

diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
index fc243ad..c6dbee6 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
@@ -27,7 +27,8 @@
         </constructor-arg>
     </bean>
 
-    <bean id="HandleResponse" parent="WebFlowInboundMessageHandlerAdaptor" scope="prototype">
+    <bean id="HandleResponse" class="net.shibboleth.sp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+            c:executionDirection="INBOUND">
         <constructor-arg>
             <bean class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain">
                 <property name="handlers">
diff --git a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
index 97add80..fa785e1 100644
--- a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
+++ b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
@@ -17,6 +17,7 @@ package net.shibboleth.sp.saml.flows.saml2;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.time.Instant;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -26,8 +27,13 @@ import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.AuthnContext;
+import org.opensaml.saml.saml2.core.NameID;
+import org.opensaml.saml.saml2.core.NameIDType;
 import org.opensaml.saml.saml2.core.Response;
 import org.opensaml.saml.saml2.core.StatusCode;
+import org.opensaml.saml.saml2.core.Subject;
+import org.opensaml.saml.saml2.core.SubjectConfirmation;
 import org.opensaml.saml.saml2.testing.SAML2ActionTestingSupport;
 import org.opensaml.security.credential.Credential;
 import org.opensaml.storage.StorageService;
@@ -48,6 +54,7 @@ import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.net.URISupport;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.sp.context.AgentRequestContext;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.flows.AbstractSPFlowTest;
@@ -81,6 +88,10 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     @Qualifier("shibboleth.StorageService")
     protected StorageService storageService;
     
+    @Autowired
+    @Qualifier("shibboleth.SessionIDGenerator")
+    protected IdentifierGenerationStrategy idGenerator;
+    
     /** Relay state manager. */
     private StorageServiceStateTokenManager stateManager;
     
@@ -122,6 +133,25 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assertOutputMessageEvent(result, AuthnEventIds.NO_POTENTIAL_FLOW);
     }
     
+    /**
+     * Test flow with error status.
+     * 
+     * @throws IOException 
+     */
+    @Test
+    public void testErrorStatus() throws IOException {
+        setDefaultAuth();
+        
+        final Response response = buildSAMLResponse("https://idp.example.org", StatusCode.RESPONDER);
+        final DDF input = buildRemotedPOSTResponse(response);
+        setApplicationRequest(APPLICATION_ID, input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+    }
+    
     /**
      * Test flow with unverified (no metadata) IdP specified.
      * 
@@ -131,7 +161,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     public void testUnverified() throws IOException {
         setDefaultAuth();
         
-        final DDF input = buildRemotedPOSTResponse("https://unknown.example.org", StatusCode.SUCCESS);
+        final DDF input = buildRemotedPOSTResponse(buildSAMLResponse("https://unknown.example.org", StatusCode.SUCCESS));
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -140,6 +170,46 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assertOutputMessageEvent(result, IdPEventIds.INVALID_PROFILE_CONFIG);
     }
     
+    /**
+     * Test flow with expired message (the issue instant is old).
+     * 
+     * @throws IOException 
+     */
+    @Test
+    public void testExpired() throws IOException {
+        setDefaultAuth();
+        
+        final Response response = buildSAMLResponse("https://idp.example.org", StatusCode.SUCCESS);
+        response.setIssueInstant(Instant.EPOCH);
+        final DDF input = buildRemotedPOSTResponse(response);
+        setApplicationRequest(APPLICATION_ID, input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+    }
+
+    /**
+     * Test flow with incorrect Destination in response.
+     * 
+     * @throws IOException 
+     */
+    @Test
+    public void testBadDestination() throws IOException {
+        setDefaultAuth();
+        
+        final Response response = buildSAMLResponse("https://idp.example.org", StatusCode.SUCCESS);
+        response.setDestination(RESPONSE_URL + "/bad");
+        final DDF input = buildRemotedPOSTResponse(response);
+        setApplicationRequest(APPLICATION_ID, input);
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+    }
+
     /**
      * Decode an encoded response and run sanity checks against it.
      * 
@@ -165,27 +235,60 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         return output;
     }
     
+    
     /**
-     * Builds a SAML response as encoded into a form POST embedded in a remoted message.
+     * Builds a SAML response with some tailored data.
      * 
+     * @param issuer issuer value
      * @param code status code string
      * 
      * @return input object suitable for token consumer flow
-     * @throws IOException 
      */
-    @Nonnull private DDF buildRemotedPOSTResponse(@Nonnull final String issuer,
-            @Nonnull final String code) throws IOException {
+    @Nonnull private Response buildSAMLResponse(@Nonnull final String issuer, @Nonnull final String code) {
         
         final Response response = SAML2ActionTestingSupport.buildResponse();
+        response.setID(idGenerator.generateIdentifier());
+        response.setIssueInstant(Instant.now());
         response.setDestination(RESPONSE_URL);
         response.setIssuer(SAML2ActionTestingSupport.buildIssuer(issuer));
         response.setStatus(SAML2ActionTestingSupport.buildStatus(code, null));
         
         if (StatusCode.SUCCESS.equals(code)) {
             final Assertion assertion = SAML2ActionTestingSupport.buildAssertion();
+            assertion.setID(idGenerator.generateIdentifier());
+
+            final Subject subject = SAML2ActionTestingSupport.buildSubject("jdoe at example.org");
+            final NameID nameID = subject.getNameID();
+            assert nameID != null;
+            nameID.setFormat(NameIDType.EMAIL);
+            
+            subject.getSubjectConfirmations().add(
+                    SAML2ActionTestingSupport.buildSubjectConfirmation(
+                            SubjectConfirmation.METHOD_BEARER, RESPONSE_URL, "192.168.1.1"));
+            
+            assertion.setSubject(subject);
+            
+            assertion.getAuthnStatements().add(
+                    SAML2ActionTestingSupport.buildAuthnStatement(
+                            Instant.now().minusSeconds(300), "192.168.1.1", AuthnContext.PPT_AUTHN_CTX));
+            
             response.getAssertions().add(assertion);
         }
-        
+
+        return response;
+    }
+    
+    /**
+     * Encodes a SAML response into a form POST embedded in a remoted message.
+     * 
+     * @param response SAML response to encode
+     * 
+     * @return input object suitable for token consumer flow
+     * 
+     * @throws IOException on error 
+     */
+    @Nonnull private DDF buildRemotedPOSTResponse(@Nonnull final Response response) throws IOException {
+                
         try (final ByteArrayOutputStream sink = new ByteArrayOutputStream()) {
             XMLObjectSupport.marshallToOutputStream(response, sink);
             final String base64 = Base64Support.encode(sink.toByteArray(), true);

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


More information about the commits mailing list