spring-projects/spring-security · error · Saml2Exception

Saml2Exception wrapping exception during encrypted attribute

Error message

Saml2Exception wrapping exception during encrypted attribute decryption

What it means

OpenSaml5Template.decryptAttributes decrypts encrypted <saml2:Attribute> values in an AttributeStatement. Any exception (typically DecryptionException) thrown by the OpenSAML Decrypter is wrapped in a Saml2Exception and rethrown. This means an encrypted attribute could not be decrypted with the available credentials.

Source

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

								throw new Saml2Exception(ex);
							}
						}
					}
				}
			}
		}

		private void decryptAttributes(AttributeStatement statement) {
			Collection<Attribute> decrypteds = new ArrayList<>();
			for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) {
				try {
					Attribute decrypted = this.decrypter.decrypt(encrypted);
					if (decrypted != null) {
						decrypteds.add(decrypted);
					}
				}
				catch (Exception ex) {
					throw new Saml2Exception(ex);
				}
			}
			statement.getAttributes().addAll(decrypteds);
		}

		private void decryptSubject(@Nullable Subject subject) {
			if (subject != null) {
				if (subject.getEncryptedID() != null) {
					try {
						NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID());
						if (decrypted != null) {
							subject.setNameID(decrypted);
						}
					}
					catch (final DecryptionException ex) {
						throw new Saml2Exception(ex);
					}
				}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Register the correct decryptionX509Credentials (private key matching the IdP's attribute-encryption certificate) on the RelyingPartyRegistration
  2. Compare the EncryptedAttribute's KeyInfo/X509 certificate with the registered decryption certificates
  3. Ensure the JVM supports the encryption/key-transport algorithm used (install JCE providers if needed)
  4. Ask the IdP to send attributes unencrypted if decryption keys cannot be shared

Example fix

// before
.registration.decryptionX509Credentials(c -> c.add(signingCertCred)) // signing only
// after
.registration.decryptionX509Credentials(c -> c.add(new Saml2X509Credential.PrivateKey(
    RSAPrivateCrtKey, decryptionCert)))
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasEncryptedAttrs = statement.getAttributes().stream()
    .anyMatch(a -> a instanceof EncryptedAttribute);
if (hasEncryptedAttrs && registration.getDecryptionX509Credentials().isEmpty())
    throw new IllegalStateException("Encrypted attributes present but no decryption credentials");

Type guard

if (attribute instanceof EncryptedAttribute enc) { /* needs decryption */ } else { /* plain attribute */ }

Try / catch

try {
    attributes = template.decryptAttributes(...);
} catch (Saml2Exception ex) {
    logger.warn("Attribute decryption failed: " + ex.getCause());
    throw ex;
}

Prevention

When it happens

Trigger: decryptAssertion -> decryptAttributes invoked on a Response whose AttributeStatement contains <saml2:EncryptedAttribute>; decryption key mismatch, unsupported encryption algorithm, or malformed encrypted data causes the underlying exception.

Common situations: IdP configured to encrypt attributes with a certificate the SP has not registered; SP registration matched by issuer with only a signing key present; IdP changed encryption algorithms (e.g. AES-256-GCM) unsupported by the JVM's crypto providers.

Related errors


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