spring-projects/spring-security · error · Saml2Exception

Saml2Exception wrapping MarshallingException while re-marsha

Error message

Saml2Exception wrapping MarshallingException while re-marshalling response after decryption

What it means

After decrypting embedded assertions, decryptResponse() re-marshals the Response via XMLObjectSupport.marshall so decrypted assertions' ID attributes are re-established at the DOM level; a MarshallingException there is wrapped in this Saml2Exception. The decryption itself succeeded but the resulting Response could not be converted back to DOM.

Source

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

					}
					count++;
				}
				catch (DecryptionException ex) {
					throw new Saml2Exception(ex);
				}
			}

			response.getAssertions().addAll(decrypteds);

			// Re-marshall the response so that any ID attributes within the decrypted
			// Assertions
			// will have their ID-ness re-established at the DOM level.
			if (!decrypteds.isEmpty()) {
				try {
					XMLObjectSupport.marshall(response);
				}
				catch (final MarshallingException ex) {
					throw new Saml2Exception(ex);
				}
			}
		}

		private void decryptAssertion(Assertion assertion) {
			for (AttributeStatement statement : assertion.getAttributeStatements()) {
				decryptAttributes(statement);
			}
			decryptSubject(assertion.getSubject());
			if (assertion.getConditions() != null) {
				for (Condition c : assertion.getConditions().getConditions()) {
					if (!(c instanceof DelegationRestrictionType delegation)) {
						continue;
					}
					for (Delegate d : delegation.getDelegates()) {
						if (d.getEncryptedID() != null) {
							try {
								NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID());

View on GitHub (pinned to 96852e8860)

Solutions

  1. Inspect ex.getCause()/stack trace for why XMLObjectSupport.marshall failed and compare the raw (encrypted) response
  2. Upgrade/align OpenSAML 5 jars so unmarshaller/marshaller registries are consistent
  3. Work around by re-building the XMLObject tree from the decrypted data instead of relying on re-marshall, or log the raw response and report to the IdP if it emits nonstandard encrypted elements
  4. Check for custom unmarshallers or extensions that produce XMLObjects with invalid namespace declarations

Example fix

// before
// assuming any response can be re-marshalled silently
// after
try {
    template.deserialize(rawResponseString);
} catch (Saml2Exception ex) {
    logger.warn("Persist raw response for diagnosis before decryption", ex);
    throw ex;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    Response decrypted = template.decrypt(response);
} catch (Saml2Exception ex) {
    logger.warn("Re-marshall after decryption failed; raw response preserved for diagnosis", ex);
    throw ex;
}

Prevention

When it happens

Trigger: Any successful decryption of at least one encrypted assertion followed by a marshalling failure — typically due to an inconsistent DOM state after decryption, namespace issues, or OpenSAML registry/marshaller problems for the decrypted content.

Common situations: Corrupted or nonstandard IdP response whose decrypted subtree cannot be re-marshalled; OpenSAML version conflicts altering marshaller behavior; custom unmarshallers producing XMLObjects that don't round-trip through marshall().

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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