{"record":{"id":"717b7fc5471063b4","repo":"spring-projects/spring-security","slug":"unsupported-object-of-type-signable-getclass","errorCode":null,"errorMessage":"Unsupported object of type: \" + signable.getClass().getName()","messagePattern":"Unsupported object of type: \" \\+ signable\\.getClass\\(\\)\\.getName\\(\\)","errorType":"exception","errorClass":"Saml2Exception","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java","lineNumber":392,"sourceCode":"\t\t\tif (signable instanceof StatusResponseType response) {\n\t\t\t\tAssert.notNull(response.getID(), \"Response#ID cannot be null\");\n\t\t\t\tAssert.notNull(response.getIssuer(), \"Response#Issuer cannot be null\");\n\t\t\t\tAssert.notNull(response.getSignature(), \"Response#Signature cannot be null\");\n\t\t\t\treturn verifySignature(response.getID(), response.getIssuer(), response.getSignature());\n\t\t\t}\n\t\t\tif (signable instanceof RequestAbstractType request) {\n\t\t\t\tAssert.notNull(request.getID(), \"Request#ID cannot be null\");\n\t\t\t\tAssert.notNull(request.getIssuer(), \"Request#Issuer cannot be null\");\n\t\t\t\tAssert.notNull(request.getSignature(), \"Request#Signature cannot be null\");\n\t\t\t\treturn verifySignature(request.getID(), request.getIssuer(), request.getSignature());\n\t\t\t}\n\t\t\tif (signable instanceof Assertion assertion) {\n\t\t\t\tAssert.notNull(assertion.getID(), \"Assertion#ID cannot be null\");\n\t\t\t\tAssert.notNull(assertion.getIssuer(), \"Assertion#Issuer cannot be null\");\n\t\t\t\tAssert.notNull(assertion.getSignature(), \"Assertion#Signature cannot be null\");\n\t\t\t\treturn verifySignature(assertion.getID(), assertion.getIssuer(), assertion.getSignature());\n\t\t\t}\n\t\t\tthrow new Saml2Exception(\"Unsupported object of type: \" + signable.getClass().getName());\n\t\t}\n\n\t\tprivate Collection<Saml2Error> verifySignature(String id, Issuer issuer, Signature signature) {\n\t\t\tSignatureTrustEngine trustEngine = trustEngine(this.credentials);\n\t\t\tCriteriaSet criteria = verificationCriteria(issuer);\n\t\t\tCollection<Saml2Error> errors = new ArrayList<>();\n\t\t\tSAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();\n\t\t\ttry {\n\t\t\t\tprofileValidator.validate(signature);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\terrors.add(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE,\n\t\t\t\t\t\t\"Invalid signature for object [\" + id + \"]: \"));\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tif (!trustEngine.validate(signature, criteria)) {\n\t\t\t\t\terrors.add(new Saml2Error(Saml2ErrorCodes.INVALID_SIGNATURE,","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java#L374-L410","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the Assertion object, not the enclosing Response — extract response.getAssertions() and verify each assertion's signature.","If you need to verify other SAML message types (Response, LogoutRequest), implement signature validation via SignatureTrustEngine directly instead of this template's verify.","Check call sites so verify() is only invoked with org.opensaml.saml.saml2.core.Assertion instances.","Log signable.getClass().getName() at the call site to confirm which type is being passed and pick the right verification path."],"exampleFix":"// before\ntemplate.verify(response); // Response not supported\n// after\nfor (Assertion assertion : response.getAssertions()) {\n    template.verify(assertion);\n}","handlingStrategy":"type-guard","validationCode":"if (!(signable instanceof Assertion)) {\n    throw new IllegalArgumentException(\n        \"verify() supports Assertions only; got \" + signable.getClass().getName());\n}","typeGuard":"boolean isVerifiableAssertion(Object o) {\n    return o instanceof Assertion a\n            && a.getID() != null && a.getIssuer() != null && a.getSignature() != null;\n}","tryCatchPattern":"try {\n    return template.verify(signable);\n} catch (Saml2Exception ex) {\n    if (ex.getMessage().startsWith(\"Unsupported object of type\")) {\n        throw new UnsupportedOperationException(\n            \"Verify the Assertion, not \" + signable.getClass().getSimpleName());\n    }\n    throw ex;\n}","preventionTips":["Pass Assertion objects only; validate the Response envelope separately.","Check ID/Issuer/Signature are non-null before verifying.","For Responses/LogoutRequests, use a SignatureTrustEngine-based check instead of template.verify.","Add a unit test pinning the expected argument type of verify()."],"tags":["saml2","opensaml","signature-verification"],"backgroundTag":"unsupported-operation","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}