javaspring-securityspring-samlopensamlspring-security-saml2

How to access encrypted assertions after migrating to spring-security-saml2-service-provider 6.4


Background

In an application where spring-security-saml2-service-provider was upgraded from 6.3.x to 6.4.1, I am experiencing a change in behaviour where I'm struggling to access the list of encrypted assertions in a validator class.

I'm configuring a response validator in my configuration as Spring intends by:

var authProvider = new OpenSaml4AuthenticationProvider();
authProvider.setResponseValidator(responseValidator);

Having received a SAML Response with a single encrypted assertion, in said responseValidator, I'd be able to do something like this:

class SamlResponseValidator implements Converter<ResponseToken, Saml2ResponseValidatorResult> {

  @Override
  public Saml2ResponseValidatorResult convert(ResponseToken responseToken) {
    // Without any other overrides, the below gives you the Spring-decrypted assertion:
    var assertions = responseToken.getResponse().getAssertions();
    
    // In 6.3, the below would _also_ contain the still-encrypted assertions while
    // in 6.4, you'll always just get an empty list, it seems:
    var encryptedAssertions = responseToken.getResponse().getEncryptedAssertions();

    // (...)
  }
}

I can see that this change comes from what is now OpenSaml4Template.OpenSaml4DecryptionConfigurer.decryptResponse(Response response) which will do this:

// ...

int count = 0; // <-- This should probably a 1, I assume, otherwise the log statement doesn't make sense
int size = response.getEncryptedAssertions().size();
for (EncryptedAssertion encrypted : response.getEncryptedAssertions()) {
   logger.trace(String.format("Decrypting EncryptedAssertion (%d/%d) in Response [%s]", count, size, response.getID()));
   try {
      Assertion decrypted = this.decrypter.decrypt(encrypted);
      if (decrypted != null) {
         encrypteds.add(encrypted);
         decrypteds.add(decrypted);
      }
      count++;
   } catch (DecryptionException ex) {
      throw new Saml2Exception(ex);
   }
}

response.getEncryptedAssertions().removeAll(encrypteds); // <-- The cause of what I'm seeing!
response.getAssertions().addAll(decrypteds);

// ...

The Javadoc on the method states that:

The methods that follow are adapted from OpenSAML's [classes].

Previously, response.getEncryptedAssertions().removeAll(encrypteds) did not exist.

Questions

  1. Is this an intentional change in behaviour? Feels odd.
  2. What is the intended way of accessing the encrypted assertion in a validator?

More details

I know that a possible solution is to do responseToken.getToken().getSaml2Response() and parse it again.

I also now simply override the decrypter that is being used but that would mean a lot of copy and paste of code that I don't actually want to customise (and room for additional bugs and the need for additional tests).


Solution

  • I created a GitHub issue here: https://github.com/spring-projects/spring-security/issues/16367.

    Turns out that this was a more or less unintentional change that, as of writing this, will be undone with the next point release.