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
- Use an X509 certificate-based signing credential (keystore entry with private key + certificate chain).
- Check the requested credential type (getSigningCredentialType on service/config) and set it to X509.
- Inspect why getPublicKey() is null: the credential source loaded only a private or secret key.
- 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
- Prefer X509 credential type (private key + certificate) for SAML signing.
- Never point signing configuration at secret/symmetric key stores for public-key profiles.
- Verify keystore entries contain the certificate chain, not just the private key.
- Check getSigningCredentialType on the service matches the actual credential.
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
- Unable to locate signing credentials
- Unable to resolve SignatureSigningParameters, response…
- Public and private keys do not match
- Could not decode provided KeyFile
- Unable to resolve the encryption [public] key for entity id
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)