{"record":{"id":"8cbfe6d5a533bcc2","repo":"apereo/cas","slug":"signing-credentials-for-validation-could-not-be-re-8cbfe6","errorCode":null,"errorMessage":"Signing credentials for validation could not be resolved based on the provided signature","messagePattern":"Signing credentials for validation could not be resolved based on the provided signature","errorType":"exception","errorClass":"SamlException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-saml-idp-web/src/main/java/org/apereo/cas/support/saml/web/idp/profile/builders/enc/validate/SamlObjectSignatureValidator.java","lineNumber":207,"sourceCode":"        FunctionUtils.throwIf(!foundValidCredential, () -> {\n            LOGGER.error(\"No valid credentials could be found to verify the signature for [{}]\", profileRequest.getIssuer());\n            return new SamlException(\"No valid signing credentials for authentication request validation could be resolved\");\n        });\n        return true;\n    }\n\n    private boolean validateSignatureOnProfileRequest(final RequestAbstractType profileRequest,\n                                                   final Signature signature,\n                                                   final RoleDescriptorResolver roleDescriptorResolver) throws Throwable {\n        val validator = new SAMLSignatureProfileValidator();\n        LOGGER.debug(\"Validating profile signature for [{}] via [{}]...\", profileRequest.getIssuer(),\n            validator.getClass().getSimpleName());\n        validator.validate(signature);\n        LOGGER.debug(\"Successfully validated profile signature for [{}].\", profileRequest.getIssuer());\n\n        val credentials = getSigningCredential(roleDescriptorResolver, profileRequest);\n        if (credentials.isEmpty()) {\n            throw new SamlException(\"Signing credentials for validation could not be resolved based on the provided signature\");\n        }\n\n        var foundValidCredential = false;\n        val it = credentials.iterator();\n        while (!foundValidCredential && it.hasNext()) {\n            try {\n                val credential = it.next();\n                LOGGER.debug(\"Validating signature using credentials for [{}]\", credential.getEntityId());\n                SignatureValidator.validate(signature, credential);\n                LOGGER.info(\"Successfully validated the request signature.\");\n                foundValidCredential = true;\n            } catch (final Exception e) {\n                LOGGER.debug(e.getMessage(), e);\n            }\n        }\n\n        FunctionUtils.throwIf(!foundValidCredential, () -> {\n            LOGGER.error(\"No valid credentials could be found to verify the signature for [{}]\", profileRequest.getIssuer());","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-saml-idp-web/src/main/java/org/apereo/cas/support/saml/web/idp/profile/builders/enc/validate/SamlObjectSignatureValidator.java#L189-L225","documentation":"In validateSignatureOnProfileRequest, the signature itself was already cryptographically validated, but the validator then re-resolves the signing credential(s) for the peer via getSigningCredential. If none resolve from the role descriptor resolver, this SamlException is thrown. It indicates the peer's metadata does not expose a usable signing credential matching the provided signature.","triggerScenarios":"verifySamlProfileRequest -> validateSignatureOnProfileRequest when getSigningCredential(roleDescriptorResolver, profileRequest) returns empty after signature validation: peer metadata has no signing KeyDescriptor, credentials don't match the signing key, or the issuer/entity ID is not in the metadata provider.","commonSituations":"IdP-initiated or profile requests from a peer whose metadata lacks signing certs; metadata staleness after key rollover (old cert removed before CAS reloaded); entity ID typo so the resolver finds no role descriptor; signing with a key not published in metadata.","solutions":["Ensure the peer metadata publishes the exact certificate used to sign as a signing KeyDescriptor","Reload/refresh the peer metadata so the current signing cert is available","Verify the issuer entity ID in the request matches a loaded metadata record","Check SAML service registration (metadata location, entity ID regex) resolves this issuer","If keys were rolled over, keep the old cert in metadata until all peers have switched"],"exampleFix":"// before: request signed with unpublished key, resolver finds nothing\ncredentials.isEmpty() -> throw SamlException(...)\n// after: publish the signing cert in the peer's metadata\n<KeyDescriptor use=\"signing\"><ds:KeyInfo><ds:X509Data><ds:X509Certificate>...(cert matching signature key)...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor>","handlingStrategy":"validation","validationCode":"// ensure the signing key is published in peer metadata before sending signed profile requests\nval cert = X509Support.decodeCertificate(peerSigningCert);\nassert peerMetadataSigningCerts.stream().anyMatch(c -> c.equals(cert)) : \"Signing cert not in peer metadata\";","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always sign with keys published in your metadata; keep rollovers staged (publish before signing)","Reload metadata after key rollover on both sides","Log the issuer entity ID on signature failures to spot entity-ID mismatches quickly"],"tags":["saml","signature-validation","sp-metadata","credentials"],"backgroundTag":"missing-credentials","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}