apereo/cas · error · SamlException

Unable to resolve the encryption [public] key for entity id

Error message

Unable to resolve the encryption [public] key for entity id 

What it means

While building the encrypter, configureKeyEncryptionCredential resolves the SP peer's encryption public key. If the credential or its public key is null (SP metadata has no encryption key), the method returns null when encryption is optional, otherwise throws SamlException naming the peer entityID.

Solutions

  1. Publish an encryption certificate in the SP metadata (KeyDescriptor use="encryption") and refresh CAS's metadata cache.
  2. Set encryptionOptional=true on the registered service if unencrypted assertions are acceptable.
  3. Confirm the peerEntityId used for the lookup matches the SP's entityID in metadata.
  4. Check the metadata adaptor (file/MDQ/Dynamic) actually contains the SP entry with its certificate.

Example fix

// before
<md:KeyDescriptor use="signing">...</md:KeyDescriptor> <!-- only signing key in SP metadata -->
// after
<md:KeyDescriptor use="encryption"><ds:KeyInfo><ds:X509Data>...</ds:X509Data></ds:KeyInfo></md:KeyDescriptor>
Defensive patterns

Strategy: try-catch

Validate before calling

val credential = metadataResolver.getEncryptionCredential(peerEntityId, service);
if ((credential == null || credential.getPublicKey() == null) && !service.isEncryptionOptional())
    throw new IllegalStateException("No encryption public key for " + peerEntityId + "; fix SP metadata first");

Type guard

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

Try / catch

try {
    val encCred = encrypter.configureKeyEncryptionCredential(peerEntityId, service, adaptor);
    if (encCred == null) LOGGER.warn("Encryption skipped (optional) for {}", peerEntityId);
} catch (SamlException e) {
    LOGGER.error("SP [{}] has no encryption key in metadata; request updated metadata", peerEntityId, e);
}

Prevention

When it happens

Trigger: buildEncrypterForSamlObject → configureKeyEncryptionCredential is called for a peer entity whose metadata/key source yields no credential or a credential with null publicKey, and service.isEncryptionOptional() is false.

Common situations: SP metadata missing KeyDescriptor use=encryption; stale/misindexed metadata so the SP's encryption cert isn't found; entityID mismatch causing lookup against the wrong entity; service requiring encryption though SP never published an encryption key.

Related errors


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

        mdCredentialResolver.setRoleDescriptorResolver(roleDescriptorResolver);
        mdCredentialResolver.initialize();

        val criteriaSet = new CriteriaSet();
        criteriaSet.add(new EncryptionConfigurationCriterion(encryptionConfiguration));
        criteriaSet.add(new EntityIdCriterion(peerEntityId));
        criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME));
        criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION));
        criteriaSet.add(new SamlIdPSamlRegisteredServiceCriterion(service));

        LOGGER.debug("Attempting to resolve the encryption key for entity id [{}]", peerEntityId);
        val credential = mdCredentialResolver.resolveSingle(criteriaSet);

        if (credential == null || credential.getPublicKey() == null) {
            if (service.isEncryptionOptional()) {
                LOGGER.warn("Unable to resolve the encryption [public] key for entity id [{}]", peerEntityId);
                return null;
            }
            throw new SamlException("Unable to resolve the encryption [public] key for entity id " + peerEntityId);
        }

        val encodedKey = EncodingUtils.encodeBase64(credential.getPublicKey().getEncoded());
        LOGGER.debug("Found encryption public key: [{}]", encodedKey);
        encryptionConfiguration.setKeyTransportEncryptionCredentials(CollectionUtils.wrapList(credential));
        return credential;
    }

    /**
     * Resolve encryption parameters.
     *
     * @param service                 the service
     * @param encryptionConfiguration the encryption configuration
     * @return the encryption parameters
     * @throws ResolverException the exception
     */
    protected EncryptionParameters resolveEncryptionParameters(final SamlRegisteredService service,
                                                               final BasicEncryptionConfiguration encryptionConfiguration)

View on GitHub (pinned to e7288fc434)