[java-identity-provider] branch main updated: IDP-2351 - Allow per-AuthenticationResult lifetime/timeout policies

Scott Cantor cantor.2 at osu.edu
Wed Mar 12 15:39:48 UTC 2025


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=a14cede77d43c90569f68051ba0706d8baaf6afe

The following commit(s) were added to refs/heads/main by this push:
     new a14cede77 IDP-2351 - Allow per-AuthenticationResult lifetime/timeout policies
a14cede77 is described below

commit a14cede77d43c90569f68051ba0706d8baaf6afe
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Mar 12 11:39:42 2025 -0400

    IDP-2351 - Allow per-AuthenticationResult lifetime/timeout policies
    
    https://shibboleth.atlassian.net/browse/IDP-2351
    
    Implement support via External method.
---
 .../idp/authn/AbstractValidationAction.java        |  7 ++-
 .../idp/authn/ExternalAuthentication.java          | 19 +++++-
 .../context/ExternalAuthenticationContext.java     | 60 ++++++++++++++++++
 .../idp/authn/impl/ExternalAuthenticationImpl.java | 71 ++++++++++------------
 .../authn/impl/ValidateExternalAuthentication.java | 20 +++---
 5 files changed, 126 insertions(+), 51 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractValidationAction.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractValidationAction.java
index 1a19ffcca..14e20e72a 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractValidationAction.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractValidationAction.java
@@ -385,8 +385,11 @@ public abstract class AbstractValidationAction extends AbstractAuthenticationAct
      * 
      * @param profileRequestContext the current profile request context
      * @param authenticationContext the current authentication context
+     * 
+     * @return the new result
      */
-    protected void buildAuthenticationResult(@Nonnull final ProfileRequestContext profileRequestContext,
+    @Nonnull protected AuthenticationResult buildAuthenticationResult(
+            @Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
         
         final AuthenticationFlowDescriptor attemptedFlow = authenticationContext.getAttemptedFlow();
@@ -424,6 +427,8 @@ public abstract class AbstractValidationAction extends AbstractAuthenticationAct
         
         Constraint.isNotNull(authenticationContext.getParent(),
                 "Parent context cannot be null").addSubcontext(c14n, true);
+        
+        return result;
     }
     
     /**
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
index 91bdb03c6..476d5f86e 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
@@ -58,13 +58,27 @@ public abstract class ExternalAuthentication {
     /** Request attribute to which an authentication timestamp may be bound. */
     @Nonnull @NotEmpty public static final String AUTHENTICATION_INSTANT_KEY = "authnInstant";
     
+    /**
+     * Request attribute to which the authentication result lifetime may be bound.
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull @NotEmpty public static final String RESULT_LIFETIME_KEY = "authnLifetime";
+
+    /**
+     * Request attribute to which the authentication result timeout may be bound.
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull @NotEmpty public static final String RESULT_TIMEOUT_KEY = "authnTimeout";
+    
     /** 
      * Request attribute to which a collection of authenticating authorities may be bound.
      * 
      * @since 3.4.0
      */
     @Nonnull @NotEmpty public static final String AUTHENTICATING_AUTHORITIES_KEY = "authnAuthorities";
-
+    
     /** 
      * Request attribute to which a collection of {@link IdPAttribute} objects may be bound.
      * 
@@ -94,7 +108,7 @@ public abstract class ExternalAuthentication {
      * @since 3.2.0
      */
     @Nonnull @NotEmpty public static final String REVOKECONSENT_KEY = "revokeConsent";
-
+    
     /**
      * Request attribute to which a signal to set
      * {@link net.shibboleth.idp.authn.AuthenticationResult#setPreviousResult(boolean)} may be bound.
@@ -111,6 +125,7 @@ public abstract class ExternalAuthentication {
 
     /** Request attribute that provides the entity ID of the relying party that is requesting authentication. */
     @Nonnull @NotEmpty public static final String RELYING_PARTY_PARAM = "relyingParty";
+    
 
     /**
      * Request attribute that indicates whether we're being called as an extension of another login flow.
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
index 781570349..74f32e44a 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
@@ -15,6 +15,7 @@
 package net.shibboleth.idp.authn.context;
 
 import java.security.Principal;
+import java.time.Duration;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,6 +26,7 @@ import javax.security.auth.Subject;
 
 import org.opensaml.messaging.context.BaseContext;
 
+import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.ExternalAuthentication;
 import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.logic.Constraint;
@@ -56,6 +58,12 @@ public final class ExternalAuthenticationContext extends BaseContext {
     /** Time of authentication. */
     @Nullable private Instant authnInstant;
     
+    /** Override for result lifetime. */
+    @Nullable private Duration authnLifetime;
+
+    /** Override for result timeout. */
+    @Nullable private Duration authnTimeout;
+
     /** Proxied authenticating sources. */
     @Nonnull private Collection<String> authenticatingAuthorities;
     
@@ -206,6 +214,58 @@ public final class ExternalAuthenticationContext extends BaseContext {
         return this;
     }
     
+    /**
+     * Get a custom lifetime to apply to the built {@link AuthenticationResult}.
+     * 
+     * @return override of result lifetime
+     * 
+     * @since 5.2.0
+     */
+    @Nullable public Duration getAuthnLifetime() {
+        return authnLifetime;
+    }
+    
+    /**
+     * Set a custom lifetime to apply to the built {@link AuthenticationResult}.
+     * 
+     * @param lifetime override of result lifetime
+     * 
+     * @return this context
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull public ExternalAuthenticationContext setAuthnLifetime(@Nullable final Duration lifetime) {
+        authnLifetime = lifetime;
+        
+        return this;
+    }
+    
+    /**
+     * Get a custom timeout to apply to the built {@link AuthenticationResult}.
+     * 
+     * @return override of result timeout
+     * 
+     * @since 5.2.0
+     */
+    @Nullable public Duration getAuthnTimeout() {
+        return authnTimeout;
+    }
+    
+    /**
+     * Set a custom timeout to apply to the built {@link AuthenticationResult}.
+     * 
+     * @param timeout override of result timeout
+     * 
+     * @return this context
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull public ExternalAuthenticationContext setAuthnTimeout(@Nullable final Duration timeout) {
+        authnTimeout = timeout;
+        
+        return this;
+    }
+    
     /**
      * Get a mutable, ordered list of proxied authentication sources.
      * 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
index d2e02e1b1..fa08db859 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
@@ -16,6 +16,7 @@ package net.shibboleth.idp.authn.impl;
 
 import java.io.IOException;
 import java.security.Principal;
+import java.time.Duration;
 import java.time.Instant;
 import java.util.Collection;
 import java.util.function.Function;
@@ -115,67 +116,61 @@ public class ExternalAuthenticationImpl extends ExternalAuthentication {
             throw new ExternalAuthenticationException("No flow execution URL found to return control");
         }
         
-        Object attr = request.getAttribute(SUBJECT_KEY);
-        if (attr != null && attr instanceof Subject) {
-            extContext.setSubject((Subject) attr);
+        if (request.getAttribute(SUBJECT_KEY) instanceof Subject sub) {
+            extContext.setSubject(sub);
         } else {
-            attr = request.getAttribute(PRINCIPAL_KEY);
-            if (attr != null && attr instanceof Principal) {
-                extContext.setPrincipal((Principal) attr);
+            if (request.getAttribute(PRINCIPAL_KEY) instanceof Principal prin) {
+                extContext.setPrincipal(prin);
             } else {
-                attr = request.getAttribute(PRINCIPAL_NAME_KEY);
-                if (attr != null && attr instanceof String) {
-                    extContext.setPrincipalName((String) attr);
+                if (request.getAttribute(PRINCIPAL_NAME_KEY) instanceof String s) {
+                    extContext.setPrincipalName(s);
                 }
             }
         }
         
-        attr = request.getAttribute(AUTHENTICATION_INSTANT_KEY);
-        if (attr != null && attr instanceof Instant) {
-            extContext.setAuthnInstant((Instant) attr);
+        if (request.getAttribute(AUTHENTICATION_INSTANT_KEY) instanceof Instant ts) {
+            extContext.setAuthnInstant(ts);
         }
         
-        attr = request.getAttribute(AUTHENTICATING_AUTHORITIES_KEY);
-        if (attr != null && attr instanceof Collection<?>) {
-            extContext.getAuthenticatingAuthorities().addAll((Collection<String>) attr);
+        if (request.getAttribute(RESULT_LIFETIME_KEY) instanceof Duration dur) {
+            extContext.setAuthnLifetime(dur);
+        }
+
+        if (request.getAttribute(RESULT_TIMEOUT_KEY) instanceof Duration dur) {
+            extContext.setAuthnTimeout(dur);
+        }
+
+        if (request.getAttribute(AUTHENTICATING_AUTHORITIES_KEY) instanceof Collection<?> c) {
+            extContext.getAuthenticatingAuthorities().addAll((Collection<String>) c);
         }
         
-        attr = request.getAttribute(ATTRIBUTES_KEY);
-        if (attr != null && attr instanceof Collection<?>) {
+        if (request.getAttribute(ATTRIBUTES_KEY) instanceof Collection<?> attrs) {
             final AttributeContext ac = extContext.ensureSubcontext(AttributeContext.class);
-            ac.setUnfilteredIdPAttributes(
-                    (Collection<IdPAttribute>) attr);
-            ac.setIdPAttributes(
-                    (Collection<IdPAttribute>) attr);
+            ac.setUnfilteredIdPAttributes((Collection<IdPAttribute>) attrs);
+            ac.setIdPAttributes((Collection<IdPAttribute>) attrs);
         }
         
-        attr = request.getAttribute(AUTHENTICATION_ERROR_KEY);
-        if (attr != null && attr instanceof String) {
-            extContext.setAuthnError((String) attr);
+        if (request.getAttribute(AUTHENTICATION_ERROR_KEY) instanceof String s) {
+            extContext.setAuthnError(s);
         }
         
-        attr = request.getAttribute(AUTHENTICATION_EXCEPTION_KEY);
-        if (attr != null && attr instanceof Exception) {
-            extContext.setAuthnException((Exception) attr);
+        if (request.getAttribute(AUTHENTICATION_EXCEPTION_KEY) instanceof Exception e) {
+            extContext.setAuthnException(e);
         }
 
-        attr = request.getAttribute(AUTHENTICATION_EVENT_KEY);
-        if (attr != null && attr instanceof String) {
-            extContext.setAuthnEvent((String) attr);
+        if (request.getAttribute(AUTHENTICATION_EVENT_KEY) instanceof String s) {
+            extContext.setAuthnEvent(s);
         }
 
-        attr = request.getAttribute(DONOTCACHE_KEY);
-        if (attr != null && attr instanceof Boolean) {
-            extContext.setDoNotCache((Boolean) attr);
+        if (request.getAttribute(DONOTCACHE_KEY) instanceof Boolean flag) {
+            extContext.setDoNotCache(flag);
         }
 
-        attr = request.getAttribute(PREVIOUSRESULT_KEY);
-        if (attr != null && attr instanceof Boolean) {
-            extContext.setPreviousResult((Boolean) attr);
+        if (request.getAttribute(PREVIOUSRESULT_KEY) instanceof Boolean flag) {
+            extContext.setPreviousResult(flag);
         }
         
-        attr = request.getAttribute(REVOKECONSENT_KEY);
-        if (attr != null && attr instanceof Boolean && ((Boolean) attr).booleanValue()) {
+        if (request.getAttribute(REVOKECONSENT_KEY) instanceof Boolean flag && flag.booleanValue()) {
             final ConsentManagementContext consentCtx =
                     profileRequestContext.ensureSubcontext(ConsentManagementContext.class);
             consentCtx.setRevokeConsent(true);
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
index 6e0cf2d6e..e387d52fa 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
@@ -243,17 +243,17 @@ public class ValidateExternalAuthentication extends AbstractAuditingValidationAc
         assert extContext != null;
         filterAttributes(extContext);
         
-        buildAuthenticationResult(profileRequestContext, authenticationContext);
+        final AuthenticationResult result = buildAuthenticationResult(profileRequestContext, authenticationContext);
+        final Instant ai = extContext.getAuthnInstant();
+        if (ai != null) {
+            result.setAuthenticationInstant(ai);
+        }
         
-        final AuthenticationResult ar = authenticationContext.getAuthenticationResult();
-        if (ar != null) {
-            final Instant ai = extContext.getAuthnInstant();
-            if (ai != null) {
-                ar.setAuthenticationInstant(ai);
-            }
-            if (extContext.isPreviousResult()) {
-                ar.setPreviousResult(true);
-            }
+        result.setResultLifetime(extContext.getAuthnLifetime());
+        result.setResultTimeout(extContext.getAuthnTimeout());
+        
+        if (extContext.isPreviousResult()) {
+            result.setPreviousResult(true);
         }
     }
  // Checkstyle: ReturnCount|CyclomaticComplexity|MethodLength ON

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


More information about the commits mailing list