apereo/cas · critical · IllegalArgumentException

Unable to locate signing credentials

Error message

Unable to locate signing credentials

What it means

When building the signature signing configuration for outbound IdP messages (responses/assertions), credentials from the configured keystore/credential source are filtered by the service's allowed fingerprint(s). If nothing survives the filters — no credentials loaded or fingerprint mismatch — the signer has no way to sign and IllegalArgumentException is thrown.

Solutions

  1. Verify the IdP signing keystore path, password, and alias resolve to loadable credentials.
  2. Update the service's configured signing fingerprint to match the actual signing certificate (recompute SHA-1/SHA-256 fingerprint of the current cert).
  3. Remove an incorrect fingerprint filter from the service config so credentials are accepted.
  4. Ensure the signing credential bean is defined and reachable in the signing configuration properties.

Example fix

// before
service.setSigningCertificateFingerprint("ABCOLD123...");
// after
service.setSigningCertificateFingerprint("3FA9C2..." /* fingerprint of current signing cert */);
Defensive patterns

Strategy: validation

Validate before calling

val creds = signingConfiguration.resolveCredentials(service);
val matching = creds.stream().filter(c -> fingerprintMatches(c, service.getSigningCertificateFingerprint())).count();
if (matching == 0) throw new IllegalStateException("No signing credential matches fingerprint for " + service.getName());

Type guard

boolean hasSigningCredential(SamlRegisteredService s, List<Credential> creds) {
    return creds != null && !creds.isEmpty() && (s.getSigningCertificateFingerprint() == null
        || creds.stream().anyMatch(c -> fingerprintMatches(c, s.getSigningCertificateFingerprint())));
}

Try / catch

try {
    val signed = signer.encode(samlObject, service, adaptor, ...);
} catch (IllegalArgumentException e) {
    LOGGER.error("Signing credentials misconfigured: {}", e.getMessage());
    alertOps("IdP signing credential configuration error");
}

Prevention

When it happens

Trigger: getSignatureSigningConfiguration is invoked during response signing and finalCredentials ends up empty: the IdP signing keystore is not configured/unloadable, or SamlRegisteredServiceSigningEncryptionParamters/fingerprint filters exclude every credential via doesCredentialFingerprintMatch.

Common situations: Service configured with a signing certificate fingerprint that doesn't match the actual IdP key (common after key rotation); keystore path/password wrong so credentials list is empty; whitespace/case issues in fingerprint comparison.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/6017bf56d52fd931. 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/DefaultSamlIdPObjectSigner.java:285

        LOGGER.trace("Resolved entity id from SAML2 IdP metadata is [{}]", entityId);
        criteriaSet.add(new EntityIdCriterion(entityId));
        criteriaSet.add(new EntityRoleCriterion(IDPSSODescriptor.DEFAULT_ELEMENT_NAME));
        criteriaSet.add(new SamlIdPSamlRegisteredServiceCriterion(service));

        LOGGER.trace("Resolved signing credentials based on criteria [{}]", criteriaSet);
        val credentials = Sets.newLinkedHashSet(mdCredentialResolver.resolve(criteriaSet));
        LOGGER.trace("Resolved [{}] signing credentials", credentials.size());

        val finalCredentials = new ArrayList<Credential>();
        credentials.stream()
            .map(creds -> getResolvedSigningCredential(creds, privateKey, service))
            .filter(Objects::nonNull)
            .filter(creds -> doesCredentialFingerprintMatch(creds, service))
            .forEach(finalCredentials::add);

        if (finalCredentials.isEmpty()) {
            LOGGER.error("Unable to locate any signing credentials for service [{}]", service.getName());
            throw new IllegalArgumentException("Unable to locate signing credentials");
        }

        config.setSigningCredentials(finalCredentials);
        LOGGER.trace("Signature signing credentials configured with [{}] credentials", finalCredentials.size());
        return config;
    }

    /**
     * Gets signing private key.
     *
     * @param registeredService the registered service
     * @return the signing private key
     * @throws Throwable the throwable
     */
    protected PrivateKey getSigningPrivateKey(final SamlRegisteredService registeredService) throws Throwable {
        val samlIdp = casProperties.getAuthn().getSamlIdp();
        val signingKey = samlIdPMetadataLocator.resolveSigningKey(Optional.of(registeredService));
        val privateKeyFactoryBean = new PrivateKeyFactoryBean();

View on GitHub (pinned to e7288fc434)