spring-projects/spring-security · warning · LockedException

${ex.getStatus().getDefaultMessage()}

Error message

${ex.getStatus().getDefaultMessage()}

What it means

LdapAuthenticationProvider.doAuthentication() converts a PasswordPolicyException from the authenticator into a LockedException whose message is the password-policy status default message (e.g. 'account is locked', resolved via messages.getMessage(ex.getStatus().getErrorCode(), ...)). This indicates the LDAP password policy response reported a problem, most commonly a locked account during a bind.

Source

Thrown at ldap/src/main/java/org/springframework/security/ldap/authentication/LdapAuthenticationProvider.java:179

	}

	protected LdapAuthoritiesPopulator getAuthoritiesPopulator() {
		return this.authoritiesPopulator;
	}

	public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
		this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
	}

	@Override
	protected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken authentication) {
		try {
			return getAuthenticator().authenticate(authentication);
		}
		catch (PasswordPolicyException ex) {
			// The only reason a ppolicy exception can occur during a bind is that the
			// account is locked.
			throw new LockedException(
					this.messages.getMessage(ex.getStatus().getErrorCode(), ex.getStatus().getDefaultMessage()));
		}
		catch (UsernameNotFoundException ex) {
			if (this.hideUserNotFoundExceptions) {
				throw new BadCredentialsException(
						this.messages.getMessage("LdapAuthenticationProvider.badCredentials", "Bad credentials"));
			}
			throw ex;
		}
		catch (NamingException ex) {
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

	@Override
	protected Collection<? extends GrantedAuthority> loadUserAuthorities(DirContextOperations userData, String username,
			String password) {
		return getAuthoritiesPopulator().getGrantedAuthorities(userData, username);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Unlock the account in the directory (e.g. reset pwdAccountLockedTime in OpenLDAP or unlock in AD).
  2. Reduce lockout pressure: add rate limiting/account lockout backoff on your login endpoint.
  3. Tell the user their account is locked rather than a generic bad-credentials message.
  4. Review password policy settings (lockout duration/threshold) if lockouts are too aggressive.
  5. Verify ppolicy overlay/control is configured consistently between the app and the directory.

Example fix

// before
try {
    authManager.authenticate(token);
} catch (LockedException e) {
    log.error("login failed"); // losing the lock info
}

// after
try {
    authManager.authenticate(token);
} catch (LockedException e) {
    auditLog.record("ACCOUNT_LOCKED", username);
    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Your account is locked. Contact support.");
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    authManager.authenticate(token);
} catch (LockedException e) {
    audit.record("ACCOUNT_LOCKED", token.getName());
    throw new ResponseStatusException(HttpStatus.LOCKED, "account is locked; contact your administrator");
}

Prevention

When it happens

Trigger: The configured authenticator (BindAuthenticator with ppolicy control support) throws PasswordPolicyException; doAuthentication maps it to LockedException with ex.getStatus().getDefaultMessage(). Occurs when the directory's password policy control reports the account is locked (too many failed attempts, admin lock, or expired password policies).

Common situations: User exceeded the directory's failed-attempt threshold and was auto-locked, administrator manually locked the account, OpenLDAP ppolicy pwdLockout triggered, or repeated automated login attempts from a misbehaving client.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/ae129c2e516b689d. Report an issue: GitHub.