apereo/cas · error · IllegalArgumentException

Unable to identify the public key from the signing…

Error message

Unable to identify the public key from the signing credential

What it means

After resolving a candidate signing credential, the signer builds the appropriate OpenSAML credential type. For BASIC credential type the code requires credential.getPublicKey() to be non-null to construct a BasicCredential; a credential without a public key (e.g. secret-key based or failed keystore load artifact) cannot be used and IllegalArgumentException is thrown.

Solutions

  1. Use an X509 certificate-based signing credential (keystore entry with private key + certificate chain).
  2. Check the requested credential type (getSigningCredentialType on service/config) and set it to X509.
  3. Inspect why getPublicKey() is null: the credential source loaded only a private or secret key.
  4. Regenerate the keystore entry so it includes the certificate.

Example fix

// before
service.setSigningCredentialType(BasicCredentialCredentialTypes.BASIC);
// after
service.setSigningCredentialType(BasicCredentialCredentialTypes.X509);
Defensive patterns

Strategy: validation

Validate before calling

val cred = resolveSigningCredential(service);
if (cred == null || cred.getPublicKey() == null) throw new IllegalStateException("Configure an X509 certificate-based signing credential");

Type guard

boolean hasUsableSigningKey(Credential c) { return c != null && c.getPublicKey() != null; }

Try / catch

try {
    val cred = signer.getResolvedSigningCredential(service, adaptor);
} catch (IllegalArgumentException e) {
    LOGGER.error("Signing credential lacks a public key; check credential type and keystore entry", e);
}

Prevention

When it happens

Trigger: getResolvedSigningCredential with credential type BASIC where the resolved credential's getPublicKey() returns null — e.g. the configured credential is a symmetric/secret key or was loaded incompletely from the keystore.

Common situations: Configured cas.authn.saml.idp signing credential is actually a secret key credential while the code path requests BASIC/X509 public-key credential; keystore entry loaded without certificate; misconfigured credential type in service settings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

        }
        return config;
    }

    protected @Nullable AbstractCredential getResolvedSigningCredential(final Credential credential,
                                                                        final PrivateKey privateKey,
                                                                        final SamlRegisteredService service) {
        try {
            val samlIdp = casProperties.getAuthn().getSamlIdp();
            val credType = SamlIdPResponseProperties.SignatureCredentialTypes.valueOf(
                StringUtils.defaultIfBlank(service.getSigningCredentialType(),
                    samlIdp.getResponse().getCredentialType().name()).toUpperCase(Locale.ENGLISH));
            LOGGER.trace("Requested credential type [{}] is found for service [{}]", credType, service.getName());

            return switch (credType) {
                case BASIC -> {
                    LOGGER.debug("Building credential signing key [{}] based on requested credential type", credType);
                    if (credential.getPublicKey() == null) {
                        throw new IllegalArgumentException("Unable to identify the public key from the signing credential");
                    }
                    yield finalizeSigningCredential(new BasicCredential(credential.getPublicKey(), privateKey), credential);
                }
                case X509 -> {
                    if (credential instanceof final BasicX509Credential value) {
                        val certificate = value.getEntityCertificate();
                        LOGGER.debug("Locating signature signing certificate from credential [{}]", CertUtils.toString(certificate));
                        yield finalizeSigningCredential(new BasicX509Credential(certificate, privateKey), credential);
                    }
                    val signingCert = samlIdPMetadataLocator.resolveSigningCertificate(Optional.of(service));
                    LOGGER.debug("Locating signature signing certificate file from [{}]", signingCert);
                    val certificate = SamlUtils.readCertificate(signingCert);
                    yield finalizeSigningCredential(new BasicX509Credential(certificate, privateKey), credential);
                }
            };
        } catch (final Throwable e) {
            LoggingUtils.error(LOGGER, e);
        }

View on GitHub (pinned to e7288fc434)