apereo/cas · warning
[ ] is not eligible to authenticate as [ ]
Error message
[{}] is not eligible to authenticate as [{}] What it means
SimpleSurrogateAuthenticationService checks impersonation eligibility against an in-memory map of principal id -> allowed surrogate accounts. In canImpersonateInternal, if the authenticated principal has no entry in eligibleAccounts, it logs this warning and returns false - the principal is simply not configured to impersonate anyone. This is the expected deny path for unconfigured users, not a crash.
Solutions
- Add the principal to cas.authn.surrogate.simple.eligible-accounts with the desired surrogate accounts.
- Verify principal id casing matches the map key exactly.
- If eligibility should come from LDAP/JSON instead, switch the surrogate authentication service config rather than the simple map.
- Restart/reload CAS after editing the eligible accounts property.
Example fix
// before cas.authn.surrogate.simple.eligible-accounts.admin=user1,user2 // after cas.authn.surrogate.simple.eligible-accounts.admin=user1,user2 cas.authn.surrogate.simple.eligible-accounts.jdoe=user1
Defensive patterns
Strategy: validation
Validate before calling
boolean eligible = eligibleAccounts.containsKey(principalId)
&& eligibleAccounts.get(principalId).contains(surrogate);
if (!eligible) { /* hide impersonation UI / deny before request */ } Prevention
- Keep eligible-accounts keys aligned with authenticated principal ids
- Use exact-case usernames
- Review map contents after config reloads
When it happens
Trigger: canImpersonate(surrogate, principal, service) is invoked and eligibleAccounts.containsKey(principal.getId()) is false, i.e. the principal id is not a key in the configured eligible-accounts map.
Common situations: cas.authn.surrogate.simple.eligible-accounts does not include the authenticating user; user typo'd username casing; requests after a config reload dropped the mapping; tests/deploys using a config with fewer accounts than prod.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Unable to authorize surrogate authentication request for
- Principal is unauthorized to authenticate as
- Impersonation is not allowed for
- Missing surrogate username in credential
- LDAP response is not found or does not contain a result…
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/bd093c085f65af4d.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-surrogate-core/src/main/java/org/apereo/cas/authentication/surrogate/SimpleSurrogateAuthenticationService.java:41
private final Map<String, List> eligibleAccounts;
public SimpleSurrogateAuthenticationService(final Map<String, List> eligibleAccounts,
final ServicesManager servicesManager,
final CasConfigurationProperties casProperties,
final RegisteredServicePrincipalAccessStrategyEnforcer principalAccessStrategyEnforcer,
final ConfigurableApplicationContext applicationContext) {
super(servicesManager, casProperties, principalAccessStrategyEnforcer, applicationContext);
this.eligibleAccounts = new HashMap<>(eligibleAccounts);
}
@Override
public boolean canImpersonateInternal(final String surrogate, final Principal principal, final Optional<? extends Service> service) {
if (this.eligibleAccounts.containsKey(principal.getId())) {
val surrogates = this.eligibleAccounts.get(principal.getId());
LOGGER.debug("Surrogate accounts authorized for [{}] are [{}]", principal.getId(), surrogates);
return surrogates.contains(surrogate);
}
LOGGER.warn("[{}] is not eligible to authenticate as [{}]", principal.getId(), surrogate);
return false;
}
@Override
public Collection<String> getImpersonationAccounts(final String username, final Optional<? extends Service> service) {
if (this.eligibleAccounts.containsKey(username)) {
return this.eligibleAccounts.get(username);
}
return new ArrayList<>();
}
}
View on GitHub (pinned to e7288fc434)