{"record":{"id":"841d3590a29e4b22","repo":"spring-projects/spring-security","slug":"saml2exception-wrapping-decryptionexception-during-841d35","errorCode":null,"errorMessage":"Saml2Exception wrapping DecryptionException during encrypted NameID decryption","messagePattern":"Saml2Exception wrapping DecryptionException during encrypted NameID decryption","errorType":"exception","errorClass":"Saml2Exception","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java","lineNumber":556,"sourceCode":"\t\t\tfor (AttributeStatement statement : assertion.getAttributeStatements()) {\n\t\t\t\tdecryptAttributes(statement);\n\t\t\t}\n\t\t\tdecryptSubject(assertion.getSubject());\n\t\t\tif (assertion.getConditions() != null) {\n\t\t\t\tfor (Condition c : assertion.getConditions().getConditions()) {\n\t\t\t\t\tif (!(c instanceof DelegationRestrictionType delegation)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfor (Delegate d : delegation.getDelegates()) {\n\t\t\t\t\t\tif (d.getEncryptedID() != null) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tNameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID());\n\t\t\t\t\t\t\t\tif (decrypted != null) {\n\t\t\t\t\t\t\t\t\td.setNameID(decrypted);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (DecryptionException ex) {\n\t\t\t\t\t\t\t\tthrow new Saml2Exception(ex);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void decryptAttributes(AttributeStatement statement) {\n\t\t\tCollection<Attribute> decrypteds = new ArrayList<>();\n\t\t\tfor (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) {\n\t\t\t\ttry {\n\t\t\t\t\tAttribute decrypted = this.decrypter.decrypt(encrypted);\n\t\t\t\t\tif (decrypted != null) {\n\t\t\t\t\t\tdecrypteds.add(decrypted);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new Saml2Exception(ex);","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java#L538-L574","documentation":"OpenSaml5Template.decryptAssertion decrypts the assertion's EncryptedID (NameID) via OpenSAML's Decrypter. When OpenSAML throws a DecryptionException, it is wrapped in a Spring Security Saml2Exception and rethrown. This signals that an encrypted NameID in the assertion could not be decrypted with the configured decryption credentials.","triggerScenarios":"Calling decrypt/decryptAssertion on a Response whose Assertion contains an <saml2:EncryptedID>; the configured RelyingPartyRegistration decryption credential does not match the key the IdP used, the EncryptedData algorithm is unsupported, or the ciphertext is malformed.","commonSituations":"IdP re-keyed its encryption certificate but the SP still holds the old key; SP registered the signing credential instead of the encryption credential in RelyingPartyRegistration; wrong X509 certificate/key pair loaded from keystore; multi-tenant setups where the wrong registration is matched to the response.","solutions":["Verify RelyingPartyRegistration's decryptionX509Credentials contains the private key matching the certificate the IdP encrypted the NameID to","Check the IdP metadata/certificate to confirm which encryption key was used and import it","Test decrypting the encrypted element manually with the private key to isolate key vs. format issues","Confirm JVM JCE unlimited-strength policy / supported algorithms match the IdP's chosen encryption algorithm"],"exampleFix":"// before\nX509PasswordEncoder enc = X509PasswordEncoder.pkcs12(); // wrong or stale keystore\n.registration.signingX509Credentials(c -> c.add(signingCred)) // only signing cred\n// after\n.registration.decryptionX509Credentials(c -> c.add(\n    new X509Certificate(CertificateUtils.decodePem(encCert)),\n    keyPair.getPrivate())) // credential matching the IdP's encryption cert","handlingStrategy":"try-catch","validationCode":"// before decrypting, check that a decryption credential is registered\nif (registration.getDecryptionX509Credentials().isEmpty())\n    throw new IllegalStateException(\"No SAML decryption credentials configured\");","typeGuard":"if (assertion.getEncryptedID() == null) { /* nothing to decrypt */ return; }","tryCatchPattern":"try {\n    decrypter.decrypt(encryptedId);\n} catch (Saml2Exception ex) {\n    if (ex.getCause() instanceof DecryptionException de)\n        throw new Saml2AuthenticationException(\"Encrypted NameID decryption failed: \" + de.getMessage());\n    throw ex;\n}","preventionTips":["Always register decryptionX509Credentials, not just signing credentials","Keep SP encryption metadata in sync with the IdP after key rotation","Log DecryptionException causes to distinguish key-mismatch from algorithm issues","Test SAML responses against both staging and production IdP keys"],"tags":["saml2","decryption","encryption-credentials","spring-security"],"backgroundTag":"saml-decryption-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}