{"record":{"id":"d0eec55c2b57f223","repo":"spring-projects/spring-security","slug":"user-account-is-locked-d0eec5","errorCode":null,"errorMessage":"User account is locked","messagePattern":"User account is locked","errorType":"exception","errorClass":"LockedException","httpStatus":null,"severity":"error","filePath":"ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java","lineNumber":271,"sourceCode":"\t\t}\n\t\tMatcher matcher = SUB_ERROR_CODE.matcher(message);\n\t\tif (matcher.matches()) {\n\t\t\treturn Integer.parseInt(matcher.group(1), 16);\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate void raiseExceptionForErrorCode(int code, NamingException exception) {\n\t\tString hexString = Integer.toHexString(code);\n\t\tThrowable cause = new ActiveDirectoryAuthenticationException(hexString, exception.getMessage(), exception);\n\t\tswitch (code) {\n\t\t\tcase PASSWORD_EXPIRED -> throw new CredentialsExpiredException(this.messages\n\t\t\t\t.getMessage(\"LdapAuthenticationProvider.credentialsExpired\", \"User credentials have expired\"), cause);\n\t\t\tcase ACCOUNT_DISABLED -> throw new DisabledException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.disabled\", \"User is disabled\"), cause);\n\t\t\tcase ACCOUNT_EXPIRED -> throw new AccountExpiredException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.expired\", \"User account has expired\"), cause);\n\t\t\tcase ACCOUNT_LOCKED -> throw new LockedException(\n\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.locked\", \"User account is locked\"), cause);\n\t\t\tdefault -> throw badCredentials(cause);\n\t\t}\n\t}\n\n\tprivate String subCodeToLogMessage(int code) {\n\t\treturn switch (code) {\n\t\t\tcase USERNAME_NOT_FOUND -> \"User was not found in directory\";\n\t\t\tcase INVALID_PASSWORD -> \"Supplied password was invalid\";\n\t\t\tcase NOT_PERMITTED -> \"User not permitted to logon at this time\";\n\t\t\tcase PASSWORD_EXPIRED -> \"Password has expired\";\n\t\t\tcase ACCOUNT_DISABLED -> \"Account is disabled\";\n\t\t\tcase ACCOUNT_EXPIRED -> \"Account expired\";\n\t\t\tcase PASSWORD_NEEDS_RESET -> \"User must reset password\";\n\t\t\tcase ACCOUNT_LOCKED -> \"Account locked\";\n\t\t\tdefault -> \"Unknown (error code \" + Integer.toHexString(code) + \")\";\n\t\t};\n\t}","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java#L253-L289","documentation":"ActiveDirectoryLdapAuthenticationProvider maps AD bind-failure sub-codes to Spring Security exceptions. When AD bind fails with sub-error 775 (ACCOUNT_LOCKED, too many bad password attempts), raiseExceptionForErrorCode throws LockedException('User account is locked') wrapping the ActiveDirectoryAuthenticationException as cause.","triggerScenarios":"authenticate() -> handleBindException() -> raiseExceptionForErrorCode(ACCOUNT_LOCKED), raised when the LDAP bind against AD fails with sub-error code 775 indicating the account is locked out by the domain lockout policy.","commonSituations":"Repeated wrong-password logins triggering AD lockout policy; a service with stale credentials retrying continuously and locking the account; user locked out across the domain by attacker lockout or misconfigured app.","solutions":["Wait for the AD lockout duration to pass or have an admin unlock the account (Unlock-ADAccount).","Fix the stale/incorrect credentials in any application or scheduled job using this account to stop re-locking.","Catch LockedException separately to inform the user their account is locked rather than 'wrong password'.","Review AD lockout policy and the security event log to find the source of bad password attempts."],"exampleFix":"// before\ncatch (BadCredentialsException e) { return \"login?error\"; }\n// after\ncatch (LockedException e) { model.addAttribute(\"msg\", \"Account locked; contact helpdesk\"); return \"login\"; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return authenticationManager.authenticate(token);\n} catch (LockedException e) {\n    model.addAttribute(\"msg\", \"Account locked; contact helpdesk or retry later\");\n    return \"login\";\n}","preventionTips":["Fix stale credentials in automated jobs to prevent re-locking.","Catch LockedException separately to distinguish lockout from wrong password.","Monitor AD lockout events (4740) to find offending sources.","Implement client-side throttling to avoid contributing to lockouts."],"tags":["ldap","active-directory","account-locked","spring-security"],"backgroundTag":"permission-denied","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}