{"record":{"id":"08170664da714563","repo":"spring-projects/spring-security","slug":"metadata-response-is-missing-verification-certific","errorCode":null,"errorMessage":"Metadata response is missing verification certificates, necessary for verifying SAML assertions","messagePattern":"Metadata response is missing verification certificates, necessary for verifying SAML assertions","errorType":"exception","errorClass":"Saml2Exception","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/OpenSamlAssertingPartyDetails.java","lineNumber":113,"sourceCode":"\t\t\t\t\tverification.add(Saml2X509Credential.verification(certificate));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (UsageType.ENCRYPTION.equals(keyDescriptor.getUse())) {\n\t\t\t\tList<X509Certificate> certificates = certificates(keyDescriptor);\n\t\t\t\tfor (X509Certificate certificate : certificates) {\n\t\t\t\t\tencryption.add(Saml2X509Credential.encryption(certificate));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (UsageType.UNSPECIFIED.equals(keyDescriptor.getUse())) {\n\t\t\t\tList<X509Certificate> certificates = certificates(keyDescriptor);\n\t\t\t\tfor (X509Certificate certificate : certificates) {\n\t\t\t\t\tverification.add(Saml2X509Credential.verification(certificate));\n\t\t\t\t\tencryption.add(Saml2X509Credential.encryption(certificate));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (verification.isEmpty()) {\n\t\t\tthrow new Saml2Exception(\n\t\t\t\t\t\"Metadata response is missing verification certificates, necessary for verifying SAML assertions\");\n\t\t}\n\t\tString entityId = entity.getEntityID();\n\t\tAssert.notNull(entityId, \"EntityDescriptor#EntityID cannot be null\");\n\t\tOpenSamlAssertingPartyDetails.Builder builder = new OpenSamlAssertingPartyDetails.Builder(entity)\n\t\t\t.entityId(entityId)\n\t\t\t.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))\n\t\t\t.verificationX509Credentials((c) -> c.addAll(verification))\n\t\t\t.encryptionX509Credentials((c) -> c.addAll(encryption));\n\n\t\tList<SigningMethod> signingMethods = signingMethods(idpssoDescriptor);\n\t\tfor (SigningMethod method : signingMethods) {\n\t\t\tAssert.notNull(method.getAlgorithm(), \"EntityDescriptor declares a SigningMethod with no value\");\n\t\t\tbuilder.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm()));\n\t\t}\n\t\tif (idpssoDescriptor.getSingleSignOnServices().isEmpty()) {\n\t\t\tthrow new Saml2Exception(\n\t\t\t\t\t\"Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests\");","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/OpenSamlAssertingPartyDetails.java#L95-L131","documentation":"Spring Security SAML2 throws this Saml2Exception when parsing an asserting party's (IdP) metadata that contains no verification (validation) certificates. Verification X509 certificates are required to validate signatures on SAML assertions and responses from that IdP; without them the framework cannot trust any assertion it receives, so it refuses to build the RelyingPartyRegistration.","triggerScenarios":"Calling RelyingPartyRegistrations.fromMetadata(…)/fromMetadataLocation(…), or OpenSamlAssertingPartyDetails.withEntityDescriptor(...), on metadata whose IDPSSODescriptor has no KeyDescriptor with signing-use certificates (verification list ends up empty).","commonSituations":"IdP metadata file omits <md:KeyDescriptor use=\"signing\"> or any KeyDescriptor at all; developer hand-wrote minimal metadata; metadata endpoint returned a stub/health document; key rollover temporarily removed certs from published metadata.","solutions":["Obtain metadata from the IdP that includes signing KeyDescriptors with X509 certificates and re-import","Manually add the IdP certificate via RelyingPartyRegistration.Builder.assertingParty(details -> details.verificationX509Credentials(c -> c.add(...))) instead of relying solely on metadata","If the IdP really signs nothing (unsigned responses), configure the registration to not require signed assertions and secure the exchange another way (e.g. require POST binding over TLS with a trusted endpoint)","Verify you fetched the metadata of the actual IdP entity, not an aggregate missing per-entity KeyDescriptors"],"exampleFix":"// before (metadata without signing keys -> error)\nRelyingPartyRegistration r = RelyingPartyRegistrations.fromMetadataLocation(\"https://idp/meta\").build();\n// after: supply verification cert explicitly when metadata lacks it\nRelyingPartyRegistration r = RelyingPartyRegistration.withAssertingPartyMetadata(party -> party\n    .entityId(\"https://idp.example.com/sso\")\n    .singleSignOnServiceLocation(\"https://idp.example.com/sso\")\n    .verificationX509Credentials(c -> c.add(new Saml2X509Credential(certificate, Saml2X509CredentialType.VERIFICATION))))\n    .registrationId(\"idp\")\n    .build();","handlingStrategy":"validation","validationCode":"// Pre-check metadata contains signing certs before import\nDocument doc = parseXml(metadataBytes);\nNodeList kds = doc.getElementsByTagNameNS(\"urn:oasis:names:tc:SAML:2.0:metadata\", \"KeyDescriptor\");\nboolean hasSigningCert = false;\nfor (int i = 0; i < kds.getLength(); i++) {\n    String use = ((Element) kds.item(i)).getAttribute(\"use\");\n    if (use.isEmpty() || use.equals(\"signing\")) { hasSigningCert = true; break; }\n}\nif (!hasSigningCert) throw new IllegalArgumentException(\"Metadata has no signing certificates\");","typeGuard":null,"tryCatchPattern":"try {\n    return RelyingPartyRegistrations.fromMetadataLocation(location).build();\n} catch (Saml2Exception ex) {\n    logger.error(\"Metadata missing verification certificates; supply manually\", ex);\n    return fallbackRegistrationWithManualCert();\n}","preventionTips":["Always validate downloaded metadata contains KeyDescriptor use=signing with X509Certificate before import","Keep IdP signing certificates in your application config as a fallback to metadata","Test metadata import in CI with the real IdP metadata artifact"],"tags":["saml2","metadata","missing-certificate","spring-security"],"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"}