apereo/cas · warning

Credential attributes do not include an attribute for

Error message

Credential attributes do not include an attribute for [{}]. This will prohibit CAS to construct a meaningful authenticated principal. Examine the released claims and ensure [{}] is allowed

What it means

WsFederationCredentialsToPrincipalResolver could not build a principal id because the credential's attributes do not contain the configured principal id attribute (the WS-Federation claim). CAS logs this warning and returns null, meaning no meaningful authenticated principal can be constructed from the WS-Federation response. It typically indicates the ADFS/AD FS relying-party claim rules do not release the required claim to CAS.

Solutions

  1. On the ADFS/STS server, add an issuance authorization/transform rule that releases the required claim (e.g. Name ID or LDAP attribute mapped to the expected claim) to the CAS relying-party trust.
  2. Check the cas.authn.wsfed principal-attribute configuration value and make sure it exactly matches a claim released in the WS-Federation response (inspect the released claims in debug logs).
  3. If the claim is intentionally unavailable, change the principal attribute to one that is always released, or set principal-attribute to NameID-style default so the default principal id is used.
  4. Enable debug logging for WsFederationCredentialsToPrincipalResolver to see which claims are actually present on the credential and correct the mapping.

Example fix

// before (application.properties)
cas.authn.wsfed.principal.principal-attribute=email
// after (claim actually released by the IdP)
cas.authn.wsfed.principal.principal-attribute=http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on WS-FED principal resolution, verify the claim is released:
val attrs = credential.getAttributes();
if (!attrs.containsKey(principalAttributeName)) {
    logger.warn("Claim [{}] not released by IdP; fix ADFS issuance rules", principalAttributeName);
}
return attrs.containsKey(principalAttributeName);

Try / catch

try {
    val principal = resolver.resolve(credentials, ...);
    if (principal == null || principal.getId() == null) {
        // treat as failed resolution, fall back to alternate attribute or reject
    }
} catch (PrincipalResolutionException e) {
    logger.error("WS-FED principal resolution failed", e);
}

Prevention

When it happens

Trigger: extractPrincipalId is called after extracting WS-Federation credential attributes; the configured principal id attribute name (e.g. a claim like NameID, UPN, or a custom attribute) is absent from the credential's attribute map, so the resolver lookup returns empty and this warn path is hit.

Common situations: ADFS/STS issuing organization not releasing the claim CAS is configured to use as the principal attribute; mismatch between cas.authn.wsfed.principal.principal-attribute value and the actual claim name (case/space differences); certificate/key-dependent claim transformation not applied for the CAS relying party trust.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-wsfederation/src/main/java/org/apereo/cas/support/wsfederation/authentication/principal/WsFederationCredentialsToPrincipalResolver.java:57

        LOGGER.debug("Credential attributes provided are: [{}]", attributes);
        val idAttribute = configuration.getIdentityAttribute();
        if (attributes.containsKey(idAttribute)) {
            LOGGER.debug("Extracting principal id from attribute [{}]", this.configuration.getIdentityAttribute());
            val idAttributeAsList = CollectionUtils.toCollection(attributes.get(this.configuration.getIdentityAttribute()));
            if (idAttributeAsList.size() > 1) {
                LOGGER.warn("Found multiple values for id attribute [{}].", idAttribute);
            } else {
                LOGGER.debug("Found principal id attribute as [{}]", idAttributeAsList);
            }

            val result = CollectionUtils.firstElement(idAttributeAsList);
            if (result.isPresent()) {
                val principalId = result.get().toString();
                LOGGER.debug("Principal Id extracted from credentials: [{}]", principalId);
                return principalId;
            }
        }
        LOGGER.warn("Credential attributes do not include an attribute for [{}]. "
            + "This will prohibit CAS to construct a meaningful authenticated principal. "
            + "Examine the released claims and ensure [{}] is allowed", idAttribute, idAttribute);
        return null;
    }

    @Override
    protected Map<String, List<Object>> retrievePersonAttributes(final String principalId,
                                                                 final Credential credential,
                                                                 final Optional<Principal> currentPrincipal,
                                                                 final Map<String, List<Object>> queryAttributes,
                                                                 final Optional<Service> service,
                                                                 final Optional<AuthenticationHandler> handler) throws Throwable {
        val wsFedCredentials = (WsFederationCredential) credential;
        if (this.configuration.getAttributesType() == WsFederationConfiguration.WsFedPrincipalResolutionAttributesType.WSFED) {
            return wsFedCredentials.getAttributes();
        }
        if (this.configuration.getAttributesType() == WsFederationConfiguration.WsFedPrincipalResolutionAttributesType.CAS) {
            return super.retrievePersonAttributes(principalId, credential, currentPrincipal, new HashMap<>(), service, handler);

View on GitHub (pinned to e7288fc434)