apereo/cas · error · SamlException

Signing credentials for validation could not be resolved…

Error message

Signing credentials for validation could not be resolved based on the provided signature

What it means

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.

Solutions

  1. Ensure the peer metadata publishes the exact certificate used to sign as a signing KeyDescriptor
  2. Reload/refresh the peer metadata so the current signing cert is available
  3. Verify the issuer entity ID in the request matches a loaded metadata record
  4. Check SAML service registration (metadata location, entity ID regex) resolves this issuer
  5. If keys were rolled over, keep the old cert in metadata until all peers have switched

Example fix

// before: request signed with unpublished key, resolver finds nothing
credentials.isEmpty() -> throw SamlException(...)
// after: publish the signing cert in the peer's metadata
<KeyDescriptor use="signing"><ds:KeyInfo><ds:X509Data><ds:X509Certificate>...(cert matching signature key)...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor>
Defensive patterns

Strategy: validation

Validate before calling

// ensure the signing key is published in peer metadata before sending signed profile requests
val cert = X509Support.decodeCertificate(peerSigningCert);
assert peerMetadataSigningCerts.stream().anyMatch(c -> c.equals(cert)) : "Signing cert not in peer metadata";

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/8cbfe6d5a533bcc2. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-saml-idp-web/src/main/java/org/apereo/cas/support/saml/web/idp/profile/builders/enc/validate/SamlObjectSignatureValidator.java:207

        FunctionUtils.throwIf(!foundValidCredential, () -> {
            LOGGER.error("No valid credentials could be found to verify the signature for [{}]", profileRequest.getIssuer());
            return new SamlException("No valid signing credentials for authentication request validation could be resolved");
        });
        return true;
    }

    private boolean validateSignatureOnProfileRequest(final RequestAbstractType profileRequest,
                                                   final Signature signature,
                                                   final RoleDescriptorResolver roleDescriptorResolver) throws Throwable {
        val validator = new SAMLSignatureProfileValidator();
        LOGGER.debug("Validating profile signature for [{}] via [{}]...", profileRequest.getIssuer(),
            validator.getClass().getSimpleName());
        validator.validate(signature);
        LOGGER.debug("Successfully validated profile signature for [{}].", profileRequest.getIssuer());

        val credentials = getSigningCredential(roleDescriptorResolver, profileRequest);
        if (credentials.isEmpty()) {
            throw new SamlException("Signing credentials for validation could not be resolved based on the provided signature");
        }

        var foundValidCredential = false;
        val it = credentials.iterator();
        while (!foundValidCredential && it.hasNext()) {
            try {
                val credential = it.next();
                LOGGER.debug("Validating signature using credentials for [{}]", credential.getEntityId());
                SignatureValidator.validate(signature, credential);
                LOGGER.info("Successfully validated the request signature.");
                foundValidCredential = true;
            } catch (final Exception e) {
                LOGGER.debug(e.getMessage(), e);
            }
        }

        FunctionUtils.throwIf(!foundValidCredential, () -> {
            LOGGER.error("No valid credentials could be found to verify the signature for [{}]", profileRequest.getIssuer());

View on GitHub (pinned to e7288fc434)