Expected Behavior

Validation of a valid SAML response should not produce a warning

Current Behavior

Validation of a valid SAML response produces the following warning message twice when using spring-security-saml2-service-provider 5.5.2 with opensaml 4.1.1:

"Set of valid issuers was not available from the validation context, unable to evaluate Issuer"

Context

This message is logged by SAML20AssertionValidator in OpenSAML 4.1.1 if the ValidationContext does not contain any valid issuers in the static parameter "saml2.ValidIssuers". Apparently, this is a recent change in OpenSAML and the code in SAML20AssertionValidator tries to ensure the behavior is the same as with old versions if the parameter is not present. However, the warning is probably intended to guide implementors to use this parameter, and as an application developer I don't want to ignore warning messages from a security-relevant part of my application.

I don't see an easy workaround, because the assertionSignatureValidator in the OpenSaml4AuthenticationProvider cannot be easily changed.

Comment From: marcusdacoregio

Hi @Medo42, thanks for bringing this up.

The SAML20AssertionValidator is being used in the assertionValidator and assertionSignatureValidator. For the assertionValidator you can provide the saml2.ValidIssuers parameter in the ValidationContext this way:

@Bean
SecurityFilterChain app(HttpSecurity http) throws Exception {
    http
        .authorizeRequests((authorize) -> authorize
            .anyRequest().authenticated()
        )
        .saml2Login((saml2) -> saml2.authenticationManager(new ProviderManager(openSamlAuthenticationProvider())));

    return http.build();
}

AuthenticationProvider openSamlAuthenticationProvider() {
    OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();

    authenticationProvider.setAssertionValidator(OpenSaml4AuthenticationProvider.createDefaultAssertionValidator((assertionToken) -> {
        String audience = assertionToken.getToken().getRelyingPartyRegistration().getEntityId();
        String recipient = assertionToken.getToken().getRelyingPartyRegistration().getAssertionConsumerServiceLocation();
                String assertingPartyEntityId = assertionToken.getToken().getRelyingPartyRegistration().getAssertingPartyDetails()
                    .getEntityId();
        Map<String, Object> params = new HashMap<>();
        params.put(SAML2AssertionValidationParameters.COND_VALID_AUDIENCES, Collections.singleton(audience));
        params.put(SAML2AssertionValidationParameters.SC_VALID_RECIPIENTS, Collections.singleton(recipient));
        params.put(SAML2AssertionValidationParameters.CLOCK_SKEW, Duration.ofMinutes(5));
        params.put(SAML2AssertionValidationParameters.VALID_ISSUERS, Collections.singleton(assertingPartyEntityId));
        return new ValidationContext(params);
    }));

    return authenticationProvider;
}

This just adds the saml2.ValidIssuers on top of the default configuration from https://github.com/spring-projects/spring-security/blob/0364518b6993e8d127828be0ace45680abee9107/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java#L394-L400

For the assertionSignatureValidator I've opened #10264 to discuss the possibility to provide a custom implementation.

Comment From: marcusdacoregio

Hi @Medo42, this is now fixed via #10335. The 5.6.0-RC1 version of Spring Security contains the change.