apereo/cas · warning

Skipped metadata SignatureValidationFilter since signature…

Error message

Skipped metadata SignatureValidationFilter since signature cannot be located for [{}]

What it means

This is a WARN log from BaseSamlRegisteredServiceMetadataResolver.addSignatureValidationFilterIfNeeded, emitted when the service requests signature validation but no signature verification key/certificate can be located in its configuration. The SignatureValidationFilter is skipped entirely, so incoming metadata signatures are NOT verified for that service — a security-relevant downgrade. Metadata processing continues without signature enforcement.

Solutions

  1. Configure the signature verification certificate/key for the service (metadataSignatureValidationPublicKey or equivalent) in the service definition.
  2. Verify the key file path exists and is readable by the CAS process user.
  3. If using a keystore, confirm the alias and password resolve to a valid certificate.
  4. Re-save and reload the service, then confirm the DEBUG log 'Added metadata SignatureValidationFilter' appears.
  5. Do not ignore this warning in production if signed metadata is a security requirement; treat it as a misconfiguration.

Example fix

// before: signature validation requested but no key configured
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "https://sp.example.org/metadata",
  "requireSignedRoot": true
}
// after
{
  "@class": "org.apereo.cas.support.saml.services.SamlRegisteredService",
  "serviceId": "https://sp.example.org/metadata",
  "requireSignedRoot": true,
  "metadataSignatureValidationPublicKey": "file:/etc/cas/sp-signing.crt"
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify signing material exists before saving a service that requires signed metadata
String keyPath = service.getMetadataSignatureValidationPublicKey();
if (service.isRequireSignedRoot() && (keyPath == null || !new java.io.File(
        new java.net.URI(keyPath.replace("file:", "")).getPath()).canRead())) {
    throw new IllegalStateException("Signed metadata required but signing key missing/unreadable for " + service.getServiceId());
}

Try / catch

try {
    var resolver = baseResolver.buildMetadataResolver(service, metadataFilters);
} catch (Exception e) {
    LOGGER.error("Failed to build metadata resolver with signature validation for {}", service.getServiceId(), e);
}

Prevention

When it happens

Trigger: Building a metadata resolver for a SamlRegisteredService with metadata signature validation enabled (isSignatureValidated or require-signed-metadata), but the signature verification key property (e.g. metadataSignatureValidationPublicKey / keystore-based cert) is unset, blank, or unreadable, so the code takes the else branch.

Common situations: Operator enabled 'require signed metadata' but forgot to upload the IdP/SP signing certificate; key file path wrong or unreadable by the CAS process; certificate stored in a keystore alias that does not exist; service cloned from a template that left the signing cert field empty.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-saml-idp-metadata/src/main/java/org/apereo/cas/support/saml/services/idp/metadata/cache/resolver/BaseSamlRegisteredServiceMetadataResolver.java:128

            filter.initialize();
            metadataFilterList.add(filter);
            LOGGER.debug("Added metadata predicate filter with direction [{}] and entity attribute conditions [{}]",
                service.getMetadataCriteriaDirection(), conditions);
        }
    }

    private static void addSignatureValidationFilterIfNeeded(final SamlRegisteredService service,
                                                             @Nullable final SignatureValidationFilter signatureValidationFilter,
                                                             final List<MetadataFilter> metadataFilterList) throws Exception {
        if (signatureValidationFilter != null) {
            if (!signatureValidationFilter.isInitialized()) {
                signatureValidationFilter.setRequireSignedRoot(service.isRequireSignedRoot());
                signatureValidationFilter.initialize();
            }
            metadataFilterList.add(signatureValidationFilter);
            LOGGER.debug("Added metadata SignatureValidationFilter for [{}]", service.getServiceId());
        } else {
            LOGGER.warn("Skipped metadata SignatureValidationFilter since signature cannot be located for [{}]", service.getServiceId());
        }
    }

    protected static void buildEntityDescriptorCertificatesExpirationFilterIfNeeded(
        final SamlRegisteredService service,
        final List<MetadataFilter> metadataFilterList) throws Exception {
        if (service.isValidateMetadataCertificates()) {
            val filter = new EntityDescriptorCertificatesExpirationFilter();
            filter.initialize();
            metadataFilterList.add(filter);
            LOGGER.debug("Added EntityDescriptorCertificatesExpirationFilter for [{}]", service.getServiceId());
        }
    }

    protected static void buildSignatureValidationFilterIfNeeded(final SamlRegisteredService service,
                                                                 final List<MetadataFilter> metadataFilterList)
        throws Exception {
        if (StringUtils.isBlank(service.getMetadataSignatureLocation())) {

View on GitHub (pinned to e7288fc434)