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

Scott Cantor cantor.2 at osu.edu
Wed Mar 19 16:28:44 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=f07b66708e8968ec0762975a7a65e6798dceabaf

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

commit f07b66708e8968ec0762975a7a65e6798dceabaf
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Mar 19 12:28:41 2025 -0400

    IDP-2351 - Allow per-AuthenticationResult lifetime/timeout policies
    
    https://shibboleth.atlassian.net/browse/IDP-2351
    
    Added flow descriptor and property support for control via strategies.
---
 .../idp/authn/AbstractValidationAction.java        |  3 ++
 .../idp/authn/AuthenticationFlowDescriptor.java    | 62 ++++++++++++++++++++++
 .../net/shibboleth/idp/conf/authn-system.xml       | 28 ++++++++++
 3 files changed, 93 insertions(+)

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..b7c43b13c 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
@@ -407,6 +407,9 @@ public abstract class AbstractValidationAction extends AbstractAuthenticationAct
                     authenticationContext.isResultCacheable() ? "will" : "will not");
         }
         
+        result.setResultLifetime(attemptedFlow.getResultLifetimeLookupStrategy().apply(profileRequestContext));
+        result.setResultTimeout(attemptedFlow.getResultTimeoutLookupStrategy().apply(profileRequestContext));
+        
         final BiConsumer<ProfileRequestContext,Subject> decorator = attemptedFlow.getSubjectDecorator();
         if (decorator != null) {
             decorator.accept(profileRequestContext, result.getSubject());
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
index 62c6ec7a8..90576c3fe 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.function.BiConsumer;
 import java.util.function.BiPredicate;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
@@ -48,6 +49,7 @@ import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.logic.PredicateSupport;
 import net.shibboleth.shared.primitive.StringSupport;
 
@@ -103,6 +105,12 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
     /** Maximum amount of time since last usage that a flow should be considered active. */
     @Nonnull private Duration inactivityTimeout;
 
+    /** Lookup strategy for per-result lifetime. */
+    @Nonnull private Function<ProfileRequestContext,Duration> resultLifetimeLookupStrategy;
+
+    /** Lookup strategy for per-result timeout. */
+    @Nonnull private Function<ProfileRequestContext,Duration> resultTimeoutLookupStrategy;
+
     /**
      * Supported principals provided by delimited strings, for post-initialization override via
      * {@link PrincipalServiceManager}.
@@ -136,6 +144,8 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
         supportsNonBrowser = true;
         proxyRestrictionsEnforced = true;
         reuseCondition = new ProxyCountPredicate();
+        resultLifetimeLookupStrategy = FunctionSupport.constant(null);
+        resultTimeoutLookupStrategy = FunctionSupport.constant(null);
         supportedPrincipals = new Subject();
         activationCondition = PredicateSupport.alwaysTrue();
         final Duration thirtyMins = Duration.ofMinutes(30);
@@ -424,6 +434,58 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
 
         inactivityTimeout = timeout;
     }
+    
+    /**
+     * Get the lookup strategy to compute a per-result lifetime to apply to a given result.
+     * 
+     * @return lookup strategy
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull public Function<ProfileRequestContext,Duration> getResultLifetimeLookupStrategy() {
+        return resultLifetimeLookupStrategy;
+    }
+    
+    /**
+     * Set the lookup strategy to compute a per-result lifetime to apply to a given result.
+     * 
+     * <p>Defaults to returning null, deferring to flow default.</p>
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 5.2.0
+     */
+    public void setResultLifetimeLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        checkSetterPreconditions();
+        resultLifetimeLookupStrategy =
+                Constraint.isNotNull(strategy, "AuthenticationResult lifetime lookup strategy cannot be null");
+    }
+
+    /**
+     * Get the lookup strategy to compute a per-result timeout to apply to a given result.
+     * 
+     * @return lookup strategy
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull public Function<ProfileRequestContext,Duration> getResultTimeoutLookupStrategy() {
+        return resultTimeoutLookupStrategy;
+    }
+    
+    /**
+     * Set the lookup strategy to compute a per-result timeout to apply to a given result.
+     * 
+     * <p>Defaults to returning null, deferring to flow default.</p>
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 5.2.0
+     */
+    public void setResultTimeoutLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+        checkSetterPreconditions();
+        resultTimeoutLookupStrategy =
+                Constraint.isNotNull(strategy, "AuthenticationResult timeout lookup strategy cannot be null");
+    }
 
     /**
      * Check if a result generated by this flow is still active.
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/authn-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/authn-system.xml
index 763539d01..ddfa70a4a 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/authn-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/authn-system.xml
@@ -41,6 +41,12 @@
         </property>
     </bean>
 
+    <bean id="NullDurationLookupStrategy" parent="shibboleth.Functions.Constant">
+        <constructor-arg>
+            <null/>
+        </constructor-arg>
+    </bean>
+
     <!-- Defaulted flows. -->
     
     <bean p:id="authn/Password" parent="shibboleth.AuthenticationFlow"
@@ -55,6 +61,8 @@
             p:inactivityTimeout="%{idp.authn.Password.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.Password.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.Password.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.Password.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.Password.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.Password.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -74,6 +82,8 @@
             p:inactivityTimeout="%{idp.authn.IPAddress.inactivityTimeout:PT60S}"
             p:reuseCondition-ref="#{'%{idp.authn.IPAddress.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.IPAddress.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.IPAddress.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.IPAddress.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.IPAddress.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -93,6 +103,8 @@
             p:inactivityTimeout="%{idp.authn.Function.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.Function.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.Function.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.Function.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.Function.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.Function.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -112,6 +124,8 @@
             p:inactivityTimeout="%{idp.authn.External.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.External.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.External.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.External.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.External.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.External.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -131,6 +145,8 @@
             p:inactivityTimeout="%{idp.authn.RemoteUser.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.RemoteUser.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.RemoteUser.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.RemoteUser.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.RemoteUser.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.RemoteUser.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -150,6 +166,8 @@
             p:inactivityTimeout="%{idp.authn.RemoteUserInternal.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.RemoteUserInternal.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.RemoteUserInternal.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.RemoteUserInternal.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.RemoteUserInternal.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.RemoteUserInternal.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -169,6 +187,8 @@
             p:inactivityTimeout="%{idp.authn.SAML.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.SAML.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.SAML.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.SAML.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.SAML.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.SAML.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -188,6 +208,8 @@
             p:inactivityTimeout="%{idp.authn.SPNEGO.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.SPNEGO.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.SPNEGO.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.SPNEGO.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.SPNEGO.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.SPNEGO.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -207,6 +229,8 @@
             p:inactivityTimeout="%{idp.authn.X509.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.X509.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.X509.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.X509.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.X509.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.X509.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -226,6 +250,8 @@
             p:inactivityTimeout="%{idp.authn.X509Internal.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.X509Internal.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.X509Internal.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.X509Internal.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.X509Internal.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.X509Internal.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"
@@ -245,6 +271,8 @@
             p:inactivityTimeout="%{idp.authn.MFA.inactivityTimeout:%{idp.authn.defaultTimeout:PT30M}}"
             p:reuseCondition-ref="#{'%{idp.authn.MFA.reuseCondition:shibboleth.Conditions.TRUE}'.trim()}"
             p:activationCondition-ref="#{'%{idp.authn.MFA.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:resultLifetimeLookupStrategy-ref="#{'%{idp.authn.MFA.lifetimeStrategy:NullDurationLookupStrategy}'.trim()}"
+            p:resultTimeoutLookupStrategy-ref="#{'%{idp.authn.MFA.inactivityTimeoutStrategy:NullDurationLookupStrategy}'.trim()}"
             p:subjectDecorator="#{getObject('%{idp.authn.MFA.subjectDecorator:}'.trim())}">
         <property name="supportedPrincipalsByString">
             <bean parent="shibboleth.CommaDelimStringArray"

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


More information about the commits mailing list