[java-identity-provider] branch main updated: Refactor action to insulate it from IdP authenticaton layer.

Scott Cantor cantor.2 at osu.edu
Wed Aug 28 16:02:05 UTC 2024


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

scantor pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=932ee354da4abf1fe5c663bf5656d1de8dca4dc8

The following commit(s) were added to refs/heads/main by this push:
     new 932ee354d Refactor action to insulate it from IdP authenticaton layer.
932ee354d is described below

commit 932ee354da4abf1fe5c663bf5656d1de8dca4dc8
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 28 12:02:02 2024 -0400

    Refactor action to insulate it from IdP authenticaton layer.
---
 .../impl/ProcessAssertionsForAuthentication.java   | 78 ++++++++++++++++++----
 1 file changed, 65 insertions(+), 13 deletions(-)

diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
index 1f05a1f48..f0f1ec259 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ProcessAssertionsForAuthentication.java
@@ -19,6 +19,7 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -26,9 +27,11 @@ import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.core.xml.XMLObject;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.assertion.ValidationContext;
 import org.opensaml.saml.common.assertion.ValidationProcessingData;
@@ -37,6 +40,7 @@ import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters;
 import org.opensaml.saml.saml2.core.Assertion;
 import org.opensaml.saml.saml2.core.AuthnStatement;
 import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.Subject;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
@@ -48,7 +52,17 @@ import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
  * Perform processing of a SAML 2 Response's Assertions that have been validated by earlier actions
- * for use in finalization of SAML-based authentication by later actions. 
+ * for use in finalization of SAML-based authentication by later actions.
+ * 
+ * <p>The result of this action is to strip any invalid assertions from the response, and to preserve
+ * the "best"/selected {@link AuthnStatement} and any other content required in a pluggable manner.</p>
+ * 
+ * <p>The default behavior is to store the statement and the related {@link Subject} in a {@link SAMLAuthnContext}
+ * located by a lookup strategy.</p>
+ * 
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_MESSAGE}
+ * @post the selected statement is passed into the supplied {@link BiConsumer}
  */
 public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAction {
     
@@ -61,6 +75,9 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
     /** Lookup strategy to locate the SAML context. */
     @Nonnull private Function<ProfileRequestContext,SAMLAuthnContext> samlContextLookupStrategy;
     
+    /** "Sink" for preserving SAML objects. */
+    @Nonnull private BiConsumer<ProfileRequestContext,AuthnStatement> samlConsumer;
+    
     /** Selection strategy for multiple valid authn Assertions. */
     @Nonnull private Function<List<Assertion>,Assertion> authnAssertionSelectionStrategy;
     
@@ -70,9 +87,6 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
     /** The Response to process. */
     @NonnullBeforeExec private Response response;
     
-    /** The SAML authentication context. */
-    @NonnullBeforeExec private SAMLAuthnContext samlAuthnContext;
-    
     /**
      * Constructor.
      */
@@ -91,6 +105,8 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
         assert scls!= null;
         samlContextLookupStrategy = scls;
         
+        samlConsumer = new DefaultSAMLConsumer();
+        
         // Get the Assertion containing the earliest child AuthnStatement#SessionNotOnOrAfter,
         // with null values converted to Instant.MAX and therefore having the lowest precedence.
         authnAssertionSelectionStrategy = assertions -> assertions.stream()
@@ -155,6 +171,19 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
         checkSetterPreconditions();
         samlContextLookupStrategy = Constraint.isNotNull(strategy, "SAMLAuthnContext lookup strategy cannot be null");
     }
+    
+    /**
+     * Set the {@link BiConsumer} used to save off the SAML statemen and any related objects as a result of this action.
+     * 
+     * <p>This insulates the actiion from the specific context in which it may be used. The supplied consumer
+     * <strong>MUST</strong> establish any non-successful event via the supplied context if it fails.</p>
+     * 
+     * @param consumer consumer to set
+     */
+    public void setSAMLConsumer(@Nonnull final BiConsumer<ProfileRequestContext,AuthnStatement> consumer) {
+        checkSetterPreconditions();
+        samlConsumer = Constraint.isNotNull(consumer, "BiConsumer cannot be null");
+    }
 
     /** {@inheritDoc} */
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@@ -171,13 +200,6 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
             return false;
         }
-        
-        samlAuthnContext = samlContextLookupStrategy.apply(profileRequestContext);
-        if (samlAuthnContext == null) {
-            log.info("{} No SAMLAuthnContext available within authentication context", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
-            return false;
-        }
 
         return true;
     }
@@ -237,7 +259,7 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
             }
         }
         
-        samlAuthnContext.setAuthnStatement(authnStatement).setSubject(authnAssertion.getSubject());
+        samlConsumer.accept(profileRequestContext, authnStatement);
     }
 
     /**
@@ -260,6 +282,36 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
         
     }
     
+    /**
+     * Default implementation of a "sink" for the SAML objects preserved by this action.
+     */
+    private final class DefaultSAMLConsumer implements BiConsumer<ProfileRequestContext,AuthnStatement> {
+
+        /** {@inheritDoc} */
+        public void accept(@Nullable final ProfileRequestContext profileRequestContext,
+                @Nullable final AuthnStatement statement) {
+            
+            if (profileRequestContext == null || statement == null) {
+                log.error("{} Inputs were null", getLogPrefix());
+                return;
+            }
+            
+            final SAMLAuthnContext samlAuthnContext = samlContextLookupStrategy.apply(profileRequestContext);
+            if (samlAuthnContext == null) {
+                log.info("{} No SAMLAuthnContext available within authentication context", getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+                return;
+            }
+
+            samlAuthnContext.setAuthnStatement(statement);
+            
+            final XMLObject parent = statement.getParent();
+            if (parent instanceof Assertion assertion) {
+                samlAuthnContext.setSubject(assertion.getSubject());
+            }
+        }
+    }
+    
     /**
      * Predicate for valid assertions.
      */
@@ -281,7 +333,7 @@ public class ProcessAssertionsForAuthentication extends AbstractAuthenticationAc
         }
         
     }
-    
+        
     /**
      * Predicate for assertions containing at least 1 AuthenticationStatement.
      */

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


More information about the commits mailing list