springspring-securitysamlsaml-2.0spring-saml

Configuring SAML2: Bypassing 'InResponseTo' Validation While Retaining Default Settings in OpenSaml4AuthenticationProvider


I have a Java back end application running behind Nginx and spring security for SSO .My back end app lacks a mechanism to remember cookie sessions because of which SSO request could be initiated by one java instance and assertion might reach to other instance . The existing default implementation requires the validation of the InResponseTo attribute if it's present. The default implementation is based on http session which keep tracks of session via cookies.The purpose of keeping cookie is to remember id attribute and later match with InResponseTo to protect from replay attack. InResponseTo is optional atribute in SAML2.0 spec. I want to know if there's a way to disable the InResponseTo validation while still utilizing the default validation provided by OpenSaml4AuthenticationProvider. Notably, SAML2 considers the 'InResponseTo' attribute optional. What is the best method to maintain default validation but bypass InResponseTo through back end configuration settings?

My application basic configuration looks like below .

@Configuration
public class ApplicationConfiguration {

  @Autowired
  SamlSuccessHandler successHandler;

  @Bean
  SecurityFilterChain configure(HttpSecurity http) throws Exception {
    return http.authorizeHttpRequests(authorize -> authorize
        .anyRequest().authenticated()
    ).saml2Login(saml2->{
      saml2.loginProcessingUrl("/saml/SSO")
          .successHandler(successHandler);
    }).build();
  }
} 

application.yml

spring:
  security:
    saml2:
      relyingparty:
        registration:
          sap-account400:
            entity-id: my_entity_id
            identityprovider:
              entity-id: https://my-service.com
              singlesignon.sign-request: true
            assertingparty:
              metadata-uri: https://okta.com/1234
            decryption:
              credentials:
                - private-key-location: classpath:private_key_encryption.pem
                  certificate-location: classpath:certificate_encryption.crt
            signing:
              credentials:
                - private-key-location: classpath:private_key.pem
                  certificate-location: classpath:certificate.crt
            acs:
              location: http://localhost:8080/saml/SSO

Solution

  • To disable the InResponseTo validation, you will need to customize OpenSaml4AuthenticationProvider. By default, it validates the status code, the InResponseTo attribute, the Destination attribute, and the Issuer attribute.

    The simplest way to do this is to remove the InResponseTo validation result like so:

    @Component
    final class ResponseValidator implements Converter<Response, Saml2ResponseValidatorResult> {
        private final Converter<ResponseToken, Saml2ResponseValidatorResult> delegate = OpenSaml4AuthenticationProvider.createDefaultResponseValidator();
    
        @Override
        public Saml2ResponseValidatorResult convert(ResponseToken response) {
            Saml2ResponseValidatorResult result = this.delegate.convert(response);
            Collection<Saml2Error> errors = result.getErrors().stream()
                .filter((error) -> !error.getErrorCode().equals(INVALID_IN_RESPONSE_TO))
                .collect(Collectors.toList());
            return Saml2ResponseValidatorResult.failure(errors);
        }
    }
    
    ...
    
    @Bean
    AuthenticationProvider authenticationProvider(ResponseValidator validator) {
        OpenSaml4AuthenticationProvider authenticationProvider =
            new OpenSaml4AuthenticationProvider();
        authenticationProvider.setResponseValidator(validator);
        return authenticationProvider;
    }
    

    However, I'd recommend that you first try and configure your IdP to not include information that you do not intend to validate.

    Suggested Alternative

    Instead of disabling validation, consider storing the requests in some other shared storage (e.g. a cache) on the backend. You can customize Saml2AuthenticationRequestsRepository with relative ease to this end. To be fully SAML 2.0 compliant, a form of caching is already needed (see line 602).