spring-projects/spring-security · error · Saml2Exception

Saml2Exception wrapping DecryptionException during encrypted

Error message

Saml2Exception wrapping DecryptionException during encrypted subject-confirmation NameID decryption

What it means

decryptSubject also decrypts encrypted NameIDs inside each SubjectConfirmation; DecryptionException is wrapped in Saml2Exception. Thrown because failure to decrypt a subject-confirmation NameID prevents validating the SubjectConfirmation, which is required for bearer/HoK confirmation.

Source

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

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

		private void decryptLogoutRequest(LogoutRequest request) {
			if (request.getEncryptedID() != null) {
				try {
					NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID());
					if (decrypted != null) {
						request.setNameID(decrypted);
					}
				}
				catch (DecryptionException ex) {
					throw new Saml2Exception(ex);
				}
			}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure the decryption credential matches the certificate the IDP used for the SubjectConfirmation EncryptedID.
  2. Inspect the wrapped DecryptionException cause to target the exact failure (key vs algorithm).
  3. Refresh cached IDP metadata so rotated keys are picked up.
  4. Verify with the IDP team that subject-confirmation NameID encryption is intended and correctly configured.

Example fix

// before
// SP holds only the old certificate
// after
// re-import metadata containing the new IDP encryption cert and rebuild registration
reg = RelyingPartyRegistration.withRegistrationId("idp")
    .decryptionX509Credentials(c -> c.add(newCredentialFromRefreshedMetadata))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

Assert.notEmpty(registration.getDecryptionX509Credentials(), "decryption credentials required for SubjectConfirmation NameIDs");

Try / catch

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

Prevention

When it happens

Trigger: Calling decrypt(...) where a SubjectConfirmation's EncryptedID exists but decryption fails with the configured Decrypter.

Common situations: IDP uses distinct certificates for subject-confirmation encryption; SP missing private key; OpenSAML 5 algorithm restrictions; expired/rotated IDP keys still cached in SP metadata.

Related errors


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