spring-projects/spring-security · error · Saml2Exception

Saml2Exception wrapping DecryptionException during encrypted

Error message

Saml2Exception wrapping DecryptionException during encrypted assertion decryption

What it means

During decrypt(), each EncryptedAssertion in the Response is decrypted with the OpenSAML Decrypter; any DecryptionException is wrapped in Saml2Exception. The library throws it because a failure to decrypt an assertion means the SAML response cannot be processed into readable assertions.

Source

Thrown at saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java:518

		 */

		private void decryptResponse(Response response) {
			Collection<Assertion> decrypteds = new ArrayList<>();

			int count = 0;
			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) {
						decrypteds.add(decrypted);
					}
					count++;
				}
				catch (DecryptionException ex) {
					throw new Saml2Exception(ex);
				}
			}

			response.getAssertions().addAll(decrypteds);

			// Re-marshall the response so that any ID attributes within the decrypted
			// Assertions
			// will have their ID-ness re-established at the DOM level.
			if (!decrypteds.isEmpty()) {
				try {
					XMLObjectSupport.marshall(response);
				}
				catch (final MarshallingException ex) {
					throw new Saml2Exception(ex);
				}
			}
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Add the correct decryption credential to the RelyingPartyRegistration: decryptionX509Credentials(c -> c.add(credential)).
  2. Verify the IDP is encrypting with the certificate whose private key the SP has, and re-sync after cert rotation.
  3. Check the wrapped DecryptionException message for key-not-found vs algorithm-unsupported, and align the IDP's encryption algorithm with what the SP supports.
  4. Inspect the encrypted assertion's EncryptionMethod in raw XML to confirm algorithm/key size.

Example fix

// before
RelyingPartyRegistration registration = builder.build(); // no decryption key
// after
registration = builder
    .decryptionX509Credentials(c -> c.add(new Saml2X509Credential(privateKey, cert, Saml2X509CredentialType.DECRYPTION)))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if (registration.getDecryptionX509Credentials().isEmpty()) {
    throw new IllegalStateException("No decryption credentials configured for " + registration.getRegistrationId());
}

Try / catch

try {
    template.decrypt(response);
} catch (Saml2Exception ex) {
    Throwable cause = ex.getCause();
    if (cause instanceof DecryptionException) {
        logger.error("Assertion decryption failed: {}", cause.getMessage());
    }
}

Prevention

When it happens

Trigger: Calling decrypt(response) when any EncryptedAssertion cannot be decrypted: wrong/missing decryption key, unsupported encryption algorithm, or malformed ciphertext.

Common situations: IDP encrypts assertions with a certificate the SP does not hold the private key for; key rotated on the IDP but not the SP; decryptionX509Credentials not configured; OpenSAML 5 algorithm restrictions exclude the IDP's cipher.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/41ec496c07a940d1. Report an issue: GitHub.