{"record":{"id":"41ec496c07a940d1","repo":"spring-projects/spring-security","slug":"saml2exception-wrapping-decryptionexception-during","errorCode":null,"errorMessage":"Saml2Exception wrapping DecryptionException during encrypted assertion decryption","messagePattern":"Saml2Exception wrapping DecryptionException during encrypted assertion decryption","errorType":"exception","errorClass":"Saml2Exception","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java","lineNumber":518,"sourceCode":"\t\t */\n\n\t\tprivate void decryptResponse(Response response) {\n\t\t\tCollection<Assertion> decrypteds = new ArrayList<>();\n\n\t\t\tint count = 0;\n\t\t\tint size = response.getEncryptedAssertions().size();\n\t\t\tfor (EncryptedAssertion encrypted : response.getEncryptedAssertions()) {\n\t\t\t\tlogger.trace(String.format(\"Decrypting EncryptedAssertion (%d/%d) in Response [%s]\", count, size,\n\t\t\t\t\t\tresponse.getID()));\n\t\t\t\ttry {\n\t\t\t\t\tAssertion 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\tcount++;\n\t\t\t\t}\n\t\t\t\tcatch (DecryptionException ex) {\n\t\t\t\t\tthrow new Saml2Exception(ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresponse.getAssertions().addAll(decrypteds);\n\n\t\t\t// Re-marshall the response so that any ID attributes within the decrypted\n\t\t\t// Assertions\n\t\t\t// will have their ID-ness re-established at the DOM level.\n\t\t\tif (!decrypteds.isEmpty()) {\n\t\t\t\ttry {\n\t\t\t\t\tXMLObjectSupport.marshall(response);\n\t\t\t\t}\n\t\t\t\tcatch (final MarshallingException ex) {\n\t\t\t\t\tthrow new Saml2Exception(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java#L500-L536","documentation":"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.","triggerScenarios":"Calling decrypt(response) when any EncryptedAssertion cannot be decrypted: wrong/missing decryption key, unsupported encryption algorithm, or malformed ciphertext.","commonSituations":"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.","solutions":["Add the correct decryption credential to the RelyingPartyRegistration: decryptionX509Credentials(c -> c.add(credential)).","Verify the IDP is encrypting with the certificate whose private key the SP has, and re-sync after cert rotation.","Check the wrapped DecryptionException message for key-not-found vs algorithm-unsupported, and align the IDP's encryption algorithm with what the SP supports.","Inspect the encrypted assertion's EncryptionMethod in raw XML to confirm algorithm/key size."],"exampleFix":"// before\nRelyingPartyRegistration registration = builder.build(); // no decryption key\n// after\nregistration = builder\n    .decryptionX509Credentials(c -> c.add(new Saml2X509Credential(privateKey, cert, Saml2X509CredentialType.DECRYPTION)))\n    .build();","handlingStrategy":"validation","validationCode":"if (registration.getDecryptionX509Credentials().isEmpty()) {\n    throw new IllegalStateException(\"No decryption credentials configured for \" + registration.getRegistrationId());\n}","typeGuard":null,"tryCatchPattern":"try {\n    template.decrypt(response);\n} catch (Saml2Exception ex) {\n    Throwable cause = ex.getCause();\n    if (cause instanceof DecryptionException) {\n        logger.error(\"Assertion decryption failed: {}\", cause.getMessage());\n    }\n}","preventionTips":["Keep IDP encryption certificates and SP private keys in sync; re-import metadata after rotation.","Verify the certificate whose private key you hold is the one advertised to the IDP.","Confirm encryption algorithm support (e.g. aes128-gcm) on both sides for OpenSAML 5."],"tags":["saml2","decryption","encrypted-assertion","opensaml5"],"backgroundTag":"missing-credentials","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"}