apereo/cas · warning
Found multiple values for id attribute
Error message
Found multiple values for id attribute [{}]. What it means
WsFederationCredentialsToPrincipalResolver.extractPrincipalId() builds the principal id from a configured identity attribute. When the credential's attribute map contains multiple values for that attribute, CAS logs this warning; it still proceeds by using only the first element (CollectionUtils.firstElement). It alerts that the identity source is returning ambiguous identifiers.
Solutions
- Pick a single-valued attribute as identity attribute in cas.authn.wsfed[...].principal.principal-attribute (e.g. NameID/UPN rather than a multi-valued claim).
- Fix the IdP claim rules so only one value is issued for the identity claim.
- Review the logged idAttribute and the credential's attribute list to see which values were found and deduplicate at the IdP.
- If multi-valued is unavoidable, accept the first-value behavior knowingly or wrap the resolver with custom logic that selects deterministically.
Example fix
// before cas.authn.wsfed[0].principal.principal-attribute=memberof // after cas.authn.wsfed[0].principal.principal-attribute=upn
Defensive patterns
Strategy: validation
Validate before calling
Object idVal = attributes.get(idAttribute);
if (idVal != null && ((Collection<?>) (idVal instanceof Collection ? idVal : List.of(idVal))).size() > 1) {
throw new IllegalStateException("Identity attribute '" + idAttribute + "' has multiple values; choose a single-valued attribute.");
} Type guard
boolean isSingleValued(Object v) {
return !(v instanceof Collection<?> c) || c.size() == 1;
} Prevention
- Choose a single-valued claim (NameID/UPN) as the principal identity attribute.
- Audit IdP claim issuance rules for duplicate issuance of the identity claim.
- Log the full attribute map once in a test environment to verify attribute cardinality before going live.
When it happens
Trigger: Invoking extractPrincipalId on a credential whose attribute map holds a multi-valued entry for the configured identity attribute (configuration.getIdentityAttribute()), e.g. the IdP sends several values for the same claim such as multiple UPNs or employee IDs.
Common situations: ADFS claim rules issuing the identity claim more than once (duplicated 'Name ID' or custom attribute issuance rules); wrong identity attribute chosen so a genuinely multi-valued attribute (groups, emails) is used as the id; merged accounts at the IdP.
Related errors
- Principal resolution handled by
- Principal resolution is unable to produce a result and will…
- Issuer [ ] is invalid since the expected issuer should be […
- Ticket is issued before the allowed drift. Issued on
- Ticket is issued after the allowed drift. Retrieved on
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/3a575479bf6e6498.
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:45
@Deprecated(since = "8.0.0", forRemoval = true)
public class WsFederationCredentialsToPrincipalResolver extends PersonDirectoryPrincipalResolver {
protected WsFederationConfiguration configuration;
public WsFederationCredentialsToPrincipalResolver(final PrincipalResolutionContext context) {
super(context);
}
@Override
protected String extractPrincipalId(final Credential credentials, final Optional<Principal> currentPrincipal) {
val wsFedCredentials = (WsFederationCredential) credentials;
val attributes = wsFedCredentials.getAttributes();
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;
}
@OverrideView on GitHub (pinned to e7288fc434)