{"record":{"id":"d3e9670c4e259018","repo":"apereo/cas","slug":"accountlockedexception","errorCode":null,"errorMessage":"AccountLockedException","messagePattern":"AccountLockedException","errorType":"exception","errorClass":"AccountLockedException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-redis-authentication/src/main/java/org/apereo/cas/redis/RedisAuthenticationHandler.java","lineNumber":46,"sourceCode":"        this.redisTemplate = redisTemplate;\n    }\n\n    @Override\n    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(\n        final UsernamePasswordCredential credential,\n        final String originalPassword) throws Throwable {\n        val account = (RedisUserAccount) redisTemplate.opsForValue().get(credential.getUsername());\n        if (account == null) {\n            throw new AccountNotFoundException();\n        }\n        if (!getPasswordEncoder().matches(originalPassword, account.getPassword())) {\n            LOGGER.warn(\"Account password on record for [{}] does not match the given/encoded password\", credential.getId());\n            throw new FailedLoginException();\n        }\n        switch (account.getStatus()) {\n            case DISABLED -> throw new AccountDisabledException();\n            case EXPIRED -> throw new AccountExpiredException();\n            case LOCKED -> throw new AccountLockedException();\n            case MUST_CHANGE_PASSWORD -> throw new AccountPasswordMustChangeException();\n            case OK -> LOGGER.debug(\"Account status is OK\");\n        }\n        val principal = principalFactory.createPrincipal(account.getUsername(), account.getAttributes());\n        return createHandlerResult(credential, principal, new ArrayList<>());\n    }\n}\n","sourceCodeStart":28,"sourceCodeEnd":54,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-redis-authentication/src/main/java/org/apereo/cas/redis/RedisAuthenticationHandler.java#L28-L54","documentation":"RedisAuthenticationHandler throws AccountLockedException when the account record stored in Redis reports status LOCKED during username/password authentication. CAS maps each account state to a dedicated GeneralSecurityException so the authentication chain and lockout machinery can react appropriately. A locked account is rejected even if the supplied password is correct.","triggerScenarios":"authenticateUsernamePasswordInternal successfully loads the account from Redis and verifies the password, but account.getStatus() returns LOCKED in the switch statement.","commonSituations":"An administrator locked the user in the Redis-backed user store; an automated lockout policy flagged the account after repeated failures; stale Redis data left an old LOCKED status after the lock was lifted elsewhere.","solutions":["Unlock the account in the Redis user store (set its status to OK/ACTIVE) and retry authentication","Check why the account got locked: review CAS lockout/throttling configuration and failed-login logs","Verify the correct Redis database/index is configured so the handler reads current account data","If the status mapping is wrong in your custom Redis user service, fix the persisted status value"],"exampleFix":"// before (stored in Redis)\n{\"username\":\"jdoe\",\"status\":\"LOCKED\"}\n// after\n{\"username\":\"jdoe\",\"status\":\"OK\"}","handlingStrategy":"try-catch","validationCode":"// Check account status in Redis before authentication\nval acct = redisAccountService.findAccount(username);\nif (acct != null && acct.getStatus() == AccountStatus.LOCKED) {\n    throw new AccountLockedException(\"Account is locked\");\n}","typeGuard":"boolean isUnlockable(AccountState s) {\n    return s != null && s.getStatus() != AccountStatus.LOCKED;\n}","tryCatchPattern":"try {\n    return authenticationHandler.authenticate(credential);\n} catch (AccountLockedException e) {\n    LOGGER.warn(\"Account locked: {}\", credential.getId());\n    // route to unlock/contact-admin flow\n    throw e;\n}","preventionTips":["Monitor and alert on LOCKED account counts in Redis","Keep lockout policies consistent between CAS throttling and the user store","Audit automated systems that set LOCKED status","Clear stale lock flags when syncing accounts from upstream sources"],"tags":["authentication","redis","account-locked"],"backgroundTag":"authentication-required","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}