apereo/cas · error · AccountNotFoundException

AccountNotFoundException

Error message

AccountNotFoundException

What it means

RedisAuthenticationHandler.authenticateUsernamePasswordInternal throws AccountNotFoundException (no-arg, so the message is just the class name) when redisTemplate has no value stored under credential.getUsername() — i.e. the user account does not exist in Redis.

Solutions

  1. Provision/load the user account into Redis under the exact username key
  2. Verify CAS and the provisioning tool point at the same Redis host, port, database and key prefix
  3. Check for TTL/eviction policies (maxmemory-policy) deleting account keys
  4. Confirm the username casing matches exactly what is stored in Redis

Example fix

// provisioning (before login)
redisTemplate.opsForValue().set("jsmith", new RedisUserAccount("jsmith", encoder.encode("secret"), Status.OK, attrs));
// then CAS login with credential username 'jsmith' succeeds instead of throwing AccountNotFoundException
Defensive patterns

Strategy: validation

Validate before calling

Object raw = redisTemplate.opsForValue().get(username);
if (raw == null) {
    // account not provisioned; skip login or trigger provisioning
}

Type guard

boolean accountExists(RedisTemplate<String,Object> tpl, String username) {
    return Boolean.TRUE.equals(tpl.hasKey(username));
}

Try / catch

try {
    authHandler.authenticate(credential);
} catch (AccountNotFoundException e) {
    // 'user not registered' messaging
}

Prevention

When it happens

Trigger: A login attempt where GET <username> on the configured Redis template returns null: key never written, wrong Redis database/index configured, key expired or evicted, or key naming/prefix mismatch.

Common situations: User provisioning never loaded accounts into Redis; Redis flushed or running against the wrong logical DB (spring.data.redis.database); TTL expiry removed the account; username case sensitivity mismatch between CAS and the provisioning writer.

Understand the failure class

Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-redis-authentication/src/main/java/org/apereo/cas/redis/RedisAuthenticationHandler.java:37

 */
@Slf4j
public class RedisAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
    private final CasRedisTemplate redisTemplate;

    public RedisAuthenticationHandler(final String name,
                                      final PrincipalFactory principalFactory, final Integer order,
                                      final CasRedisTemplate redisTemplate) {
        super(name, principalFactory, order);
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
        final UsernamePasswordCredential credential,
        final String originalPassword) throws Throwable {
        val account = (RedisUserAccount) redisTemplate.opsForValue().get(credential.getUsername());
        if (account == null) {
            throw new AccountNotFoundException();
        }
        if (!getPasswordEncoder().matches(originalPassword, account.getPassword())) {
            LOGGER.warn("Account password on record for [{}] does not match the given/encoded password", credential.getId());
            throw new FailedLoginException();
        }
        switch (account.getStatus()) {
            case DISABLED -> throw new AccountDisabledException();
            case EXPIRED -> throw new AccountExpiredException();
            case LOCKED -> throw new AccountLockedException();
            case MUST_CHANGE_PASSWORD -> throw new AccountPasswordMustChangeException();
            case OK -> LOGGER.debug("Account status is OK");
        }
        val principal = principalFactory.createPrincipal(account.getUsername(), account.getAttributes());
        return createHandlerResult(credential, principal, new ArrayList<>());
    }
}

View on GitHub (pinned to e7288fc434)