spring-projects/spring-security · error · Saml2Exception

Unsupported object of type: " +…

Error message

Unsupported object of type: " + signable.getClass().getName()

What it means

OpenSaml5Template.verify(Object signable) supports signature verification for specific OpenSAML types (e.g. Assertion). If the object passed in is not one of the supported signable types, the template throws Saml2Exception('Unsupported object of type: <className>') because it has no signature verification strategy for that type.

Solutions

  1. Verify the Assertion object, not the enclosing Response — extract response.getAssertions() and verify each assertion's signature.
  2. If you need to verify other SAML message types (Response, LogoutRequest), implement signature validation via SignatureTrustEngine directly instead of this template's verify.
  3. Check call sites so verify() is only invoked with org.opensaml.saml.saml2.core.Assertion instances.
  4. Log signable.getClass().getName() at the call site to confirm which type is being passed and pick the right verification path.

Example fix

// before
template.verify(response); // Response not supported
// after
for (Assertion assertion : response.getAssertions()) {
    template.verify(assertion);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(signable instanceof Assertion)) {
    throw new IllegalArgumentException(
        "verify() supports Assertions only; got " + signable.getClass().getName());
}

Type guard

boolean isVerifiableAssertion(Object o) {
    return o instanceof Assertion a
            && a.getID() != null && a.getIssuer() != null && a.getSignature() != null;
}

Try / catch

try {
    return template.verify(signable);
} catch (Saml2Exception ex) {
    if (ex.getMessage().startsWith("Unsupported object of type")) {
        throw new UnsupportedOperationException(
            "Verify the Assertion, not " + signable.getClass().getSimpleName());
    }
    throw ex;
}

Prevention

When it happens

Trigger: Calling verify(signable) with an XMLObject that is not an Assertion (e.g. a Response, LogoutRequest, AttributeQuery, or arbitrary XMLObject) — the instanceof chain falls through to the final throw.

Common situations: Custom authentication converters verifying the Response envelope's signature instead of the Assertion's; verifying a LogoutRequest/LogoutResponse with the assertion-oriented template API; refactors that changed the argument type passed to verify; generic utility code reusing verify for non-assertion elements.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

			if (signable instanceof StatusResponseType response) {
				Assert.notNull(response.getID(), "Response#ID cannot be null");
				Assert.notNull(response.getIssuer(), "Response#Issuer cannot be null");
				Assert.notNull(response.getSignature(), "Response#Signature cannot be null");
				return verifySignature(response.getID(), response.getIssuer(), response.getSignature());
			}
			if (signable instanceof RequestAbstractType request) {
				Assert.notNull(request.getID(), "Request#ID cannot be null");
				Assert.notNull(request.getIssuer(), "Request#Issuer cannot be null");
				Assert.notNull(request.getSignature(), "Request#Signature cannot be null");
				return verifySignature(request.getID(), request.getIssuer(), request.getSignature());
			}
			if (signable instanceof Assertion assertion) {
				Assert.notNull(assertion.getID(), "Assertion#ID cannot be null");
				Assert.notNull(assertion.getIssuer(), "Assertion#Issuer cannot be null");
				Assert.notNull(assertion.getSignature(), "Assertion#Signature cannot be null");
				return verifySignature(assertion.getID(), assertion.getIssuer(), assertion.getSignature());
			}
			throw new Saml2Exception("Unsupported object of type: " + signable.getClass().getName());
		}

		private Collection<Saml2Error> verifySignature(String id, Issuer issuer, Signature signature) {
			SignatureTrustEngine trustEngine = trustEngine(this.credentials);
			CriteriaSet criteria = verificationCriteria(issuer);
			Collection<Saml2Error> errors = new ArrayList<>();
			SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
			try {
				profileValidator.validate(signature);
			}
			catch (Exception ex) {
				errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE,
						"Invalid signature for object [" + id + "]: "));
			}

			try {
				if (!trustEngine.validate(signature, criteria)) {
					errors.add(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE,

View on GitHub (pinned to 96852e8860)