[java-opensaml] branch main updated: OSJ-430 - Make InResponseTo validation optional

Scott Cantor cantor.2 at osu.edu
Thu Apr 3 19:49:23 UTC 2025


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

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

View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=276cb1ea73bb01fe790cffbee6814d8f6c394ee7

The following commit(s) were added to refs/heads/main by this push:
     new 276cb1ea7 OSJ-430 - Make InResponseTo validation optional
276cb1ea7 is described below

commit 276cb1ea73bb01fe790cffbee6814d8f6c394ee7
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Apr 3 15:49:20 2025 -0400

    OSJ-430 - Make InResponseTo validation optional
    
    https://shibboleth.atlassian.net/browse/OSJ-430
    
    Add "ignore InResponseTo" condition/parameter to assertion validator.
---
 .../SAML2AssertionValidationParameters.java        | 15 ++++-
 .../impl/AbstractSubjectConfirmationValidator.java | 39 ++++++++++---
 .../DefaultAssertionValidationContextBuilder.java  | 45 +++++++++++++--
 .../AbstractSubjectConfirmationValidatorTest.java  | 66 +++++++++++++---------
 4 files changed, 122 insertions(+), 43 deletions(-)

diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML2AssertionValidationParameters.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML2AssertionValidationParameters.java
index 6d163d8f7..82249c7ea 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML2AssertionValidationParameters.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML2AssertionValidationParameters.java
@@ -145,14 +145,23 @@ public final class SAML2AssertionValidationParameters {
     
     /**
      * Carries a {@link java.lang.Boolean} flag which indicates whether
-     * {@link org.opensaml.saml.saml2.core.SubjectConfirmationData} InResponseTo is required.
+     * {@link org.opensaml.saml.saml2.core.SubjectConfirmationData#getInResponseTo()} should be ignored.
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull @NotEmpty public static final String SC_IN_RESPONSE_TO_IGNORED =
+            STD_PREFIX + SC_INFIX + ".InResponseToIgnored";
+    
+    /**
+     * Carries a {@link java.lang.Boolean} flag which indicates whether
+     * {@link org.opensaml.saml.saml2.core.SubjectConfirmationData#getInResponseTo()} is required to be non-null.
      */
     @Nonnull @NotEmpty public static final String SC_IN_RESPONSE_TO_REQUIRED =
             STD_PREFIX + SC_INFIX + ".InResponseToRequired";
     
     /**
-     * Carries a {@link java.lang.String} whose value is the acceptable 
-     * {@link org.opensaml.saml.saml2.core.SubjectConfirmationData} InResponseTo.
+     * Carries a {@link java.lang.String} whose value is the acceptable point of comparison against
+     * {@link org.opensaml.saml.saml2.core.SubjectConfirmationData#getInResponseTo()}.
      */
     @Nonnull @NotEmpty public static final String SC_VALID_IN_RESPONSE_TO =
             STD_PREFIX + SC_INFIX + ".ValidInResponseTo";
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
index f84edb8c7..4152b4bb0 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
@@ -107,6 +107,7 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
             throws AssertionValidationException {
         
         final boolean addressRequired = isAddressRequired(context);
+        final boolean inResponseToIgnored = isInResponseToIgnored(context);
         final boolean inResponseToRequired = isInResponseToRequired(context);
         final boolean recipientRequired = isRecipientRequired(context);
         final boolean notOnOrAfterRequired = isNotOnOrAfterRequired(context);
@@ -133,14 +134,16 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
             if (result != ValidationResult.VALID) {
                 return result;
             }
-            
-            result = validateInResponseTo(confirmationData, assertion, context, inResponseToRequired);
-            if (result != ValidationResult.VALID) {
-                return result;
+
+            if (!inResponseToIgnored) {
+                result = validateInResponseTo(confirmationData, assertion, context, inResponseToRequired);
+                if (result != ValidationResult.VALID) {
+                    return result;
+                }
             }
         } else {
-            if (inResponseToRequired || recipientRequired || notOnOrAfterRequired || notBeforeRequired 
-                    || addressRequired) {
+            if ((!inResponseToIgnored && inResponseToRequired) || recipientRequired || notOnOrAfterRequired
+                    || notBeforeRequired || addressRequired) {
                 context.getValidationFailureMessages().add(
                         "SubjectConfirmationData was null and one or more data elements were required");
                 return ValidationResult.INVALID;
@@ -211,6 +214,23 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
         return flag != null ? flag : false;
     }
 
+    /**
+     * Determine whether InResponseTo is ignored.
+     * 
+     * @param context current validation context
+     * 
+     * @return true if ignored, false if not
+     * 
+     * @since 5.2.0
+     */
+    protected boolean isInResponseToIgnored(final ValidationContext context) {
+        final Boolean flag = ObjectSupport.firstNonNull(
+                (Boolean) context.getStaticParameters().get(
+                        SAML2AssertionValidationParameters.SC_IN_RESPONSE_TO_IGNORED),
+                Boolean.FALSE);
+        return flag != null ? flag : false;
+    }
+    
     /**
      * Determine whether InResponseTo is required.
      * 
@@ -227,7 +247,7 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
     }
 
     /**
-     * Validates the <code>InResponseTo</code> condition of the {@link SubjectConfirmationData}, if any is present.
+     * Validates the <code>InResponseTo</code> value of the {@link SubjectConfirmationData}, if any is present.
      * 
      * @param confirmationData confirmation data being validated
      * @param assertion assertion bearing the confirmation method
@@ -265,8 +285,9 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
             return ValidationResult.INDETERMINATE;
         }
         if (validInResponseTo == null) {
-            context.getValidationFailureMessages().add("Valid InResponseTo was not available from the validation context, " 
-                    + "unable to evaluate SubjectConfirmationData at InResponseTo");
+            context.getValidationFailureMessages().add(
+                    "Valid InResponseTo was not available from the validation context, " 
+                            + "unable to evaluate SubjectConfirmationData at InResponseTo");
             return ValidationResult.INDETERMINATE;
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/DefaultAssertionValidationContextBuilder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/DefaultAssertionValidationContextBuilder.java
index f0ca65130..4cc0a6703 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/DefaultAssertionValidationContextBuilder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/DefaultAssertionValidationContextBuilder.java
@@ -124,7 +124,10 @@ public class DefaultAssertionValidationContextBuilder
     
     /** Function for determining the valid InResponseTo value. */
     @Nullable private Function<ProfileRequestContext, String> inResponseTo;
-    
+
+    /** Predicate for determining whether an Assertion SubjectConfirmationData InResponseTo is ignored. */
+    @Nonnull private Predicate<ProfileRequestContext> inResponseToIgnored;
+
     /** Predicate for determining whether an Assertion SubjectConfirmationData InResponseTo is required. */
     @Nonnull private Predicate<ProfileRequestContext> inResponseToRequired;
     
@@ -154,6 +157,7 @@ public class DefaultAssertionValidationContextBuilder
         includeSelfEntityIDAsRecipient = PredicateSupport.alwaysFalse();
         checkAddress = PredicateSupport.alwaysTrue();
         inResponseTo = new DefaultValidInResponseToLookupFunction();
+        inResponseToIgnored = PredicateSupport.alwaysFalse();
         inResponseToRequired = PredicateSupport.alwaysFalse();
         recipientRequired = PredicateSupport.alwaysFalse();
         notOnOrAfterRequired = PredicateSupport.alwaysFalse();
@@ -163,8 +167,9 @@ public class DefaultAssertionValidationContextBuilder
         validIssuers = new DefaultValidIssuersLookupFunction();
         requireEntityIssuer = PredicateSupport.alwaysFalse();
 
-        securityParametersLookupStrategy = new ChildContextLookup<>(SecurityParametersContext.class)
-                .compose(new InboundMessageContextLookup());
+        securityParametersLookupStrategy =
+                new ChildContextLookup<>(SecurityParametersContext.class).compose(
+                        new InboundMessageContextLookup());
     }
     
     /**
@@ -381,6 +386,36 @@ public class DefaultAssertionValidationContextBuilder
         inResponseToRequired = Constraint.isNotNull(predicate, "InResponseTo required predicate was null");
     }
 
+    /**
+     * Get the predicate which determines whether an Assertion SubjectConfirmationData InResponseTo is ignored.
+     * 
+     * <p>
+     * Defaults to an always false predicate;
+     * </p>
+     * 
+     * @return the predicate
+     * 
+     * @since 5.2.0
+     */
+    @Nonnull public Predicate<ProfileRequestContext> getInResponseToIgnored() {
+        return inResponseToIgnored;
+    }
+
+    /**
+     * Set the predicate which determines whether an Assertion SubjectConfirmationData InResponseTo is ignored.
+     * 
+     * <p>
+     * Defaults to an always false predicate.
+     * </p>
+     * 
+     * @param predicate the predicate, must be non-null
+     * 
+     * @since 5.2.0
+     */
+    public void setInResponseToIgnored(@Nonnull final Predicate<ProfileRequestContext> predicate) {
+        inResponseToIgnored = Constraint.isNotNull(predicate, "InResponseTo ignored predicate was null");
+    }
+
     /**
      * Get the predicate which determines whether an Assertion SubjectConfirmationData Recipient is required.
      * 
@@ -774,7 +809,9 @@ public class DefaultAssertionValidationContextBuilder
                 Boolean.valueOf(getAddressRequired().test(input.getProfileRequestContext())));
         staticParams.put(SAML2AssertionValidationParameters.SC_VALID_ADDRESSES, validAddresses);
         staticParams.put(SAML2AssertionValidationParameters.SC_CHECK_ADDRESS, checkAddressEnabled);
-        
+
+        staticParams.put(SAML2AssertionValidationParameters.SC_IN_RESPONSE_TO_IGNORED,
+                Boolean.valueOf(getInResponseToIgnored().test(input.getProfileRequestContext())));
         staticParams.put(SAML2AssertionValidationParameters.SC_IN_RESPONSE_TO_REQUIRED,
                 Boolean.valueOf(getInResponseToRequired().test(input.getProfileRequestContext())));
         
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
index 09e41d9ea..aaf3c15be 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
@@ -53,7 +53,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -63,7 +63,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -73,7 +73,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -97,7 +97,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -108,7 +108,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -118,7 +118,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -130,7 +130,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -142,7 +142,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -152,7 +152,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -164,7 +164,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -175,7 +175,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -185,7 +185,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -221,7 +221,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -231,7 +231,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -243,7 +243,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -255,7 +255,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -267,7 +267,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -277,7 +277,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -289,7 +289,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -301,7 +301,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -311,9 +311,21 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
-    
+
+    @Test
+    public void testInvalidInResponseToButIgnored() throws AssertionValidationException {
+        getSubjectConfirmationData().setInResponseTo("invalid");
+        
+        Map<String,Object> staticParams = buildBasicStaticParameters();
+        staticParams.put(SAML2AssertionValidationParameters.SC_IN_RESPONSE_TO_IGNORED, Boolean.valueOf(true));
+        ValidationContext validationContext = new ValidationContext(staticParams);
+        
+        Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
+                ValidationResult.VALID);
+    }
+
     @Test
     public void testInvalidInResponseToParamType() throws AssertionValidationException {
         Map<String,Object> staticParams = buildBasicStaticParameters();
@@ -323,7 +335,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -334,7 +346,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INDETERMINATE);        
+                ValidationResult.INDETERMINATE);
     }
     
     @Test
@@ -344,7 +356,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.VALID);        
+                ValidationResult.VALID);
     }
     
     @Test
@@ -356,7 +368,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Test
@@ -368,7 +380,7 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
         ValidationContext validationContext = new ValidationContext(staticParams);
         
         Assert.assertEquals(validator.validate(subjectConfirmation, getAssertion(), validationContext), 
-                ValidationResult.INVALID);        
+                ValidationResult.INVALID);
     }
     
     @Nonnull private SubjectConfirmationData getSubjectConfirmationData() {

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


More information about the commits mailing list