spring-projects/spring-security · error · Saml2Exception

Saml2Exception wrapping DecryptionException during encrypted

Error message

Saml2Exception wrapping DecryptionException during encrypted subject NameID decryption

What it means

OpenSaml5Template.decryptSubject decrypts the <saml2:Subject>'s <saml2:EncryptedID>. A DecryptionException from the OpenSAML Decrypter is wrapped in a Saml2Exception. This means the encrypted NameID at the subject level of the assertion could not be decrypted.

Source

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

				}
				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);
					}
				}

				for (final SubjectConfirmation sc : subject.getSubjectConfirmations()) {
					if (sc.getEncryptedID() != null) {
						try {
							NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID());
							if (decrypted != null) {
								sc.setNameID(decrypted);
							}
						}
						catch (final DecryptionException ex) {
							throw new Saml2Exception(ex);
						}
					}
				}
			}
		}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure the IdP's NameID encryption certificate matches an entry in RelyingPartyRegistration.decryptionX509Credentials
  2. Re-publish updated SP encryption metadata to the IdP after key rotation
  3. Inspect the caught DecryptionException cause to distinguish 'no key' from 'bad algorithm/ciphertext'
  4. Verify the response's issuer maps to the registration holding the right keys

Example fix

// before
.metadata.input(...) // SP metadata exposes stale encryption cert
// after
.metadata.input(...) .processing(ctx -> ctx.decryptionX509Credentials(c -> c.add(newCred))) // refresh creds and republish metadata
Defensive patterns

Strategy: try-catch

Validate before calling

if (assertion.getSubject() != null && assertion.getSubject().getEncryptedID() != null
    && registration.getDecryptionX509Credentials().isEmpty())
    throw new IllegalStateException("Encrypted subject NameID but no decryption credentials");

Type guard

if (subject.getEncryptedID() == null || subject.getNameID() != null) { /* already resolvable */ }

Try / catch

try {
    decryptSubject(subject);
} catch (Saml2Exception ex) {
    throw new Saml2Exception("Failed to decrypt subject NameID: " + ex.getCause(), ex);
}

Prevention

When it happens

Trigger: decryptAssertion -> decryptSubject on a Response where the Subject carries an EncryptedID; the decrypter lacks the matching private key, or the encrypted element uses an unsupported/malformed format.

Common situations: IdP configured with 'encrypt NameID' but SP never shared the correct encryption certificate in metadata; SP key rotated without updating IdP metadata; wrong RelyingPartyRegistration resolved for the response.

Related errors


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