spring-projects/spring-security · error · BadCredentialsException
Empty Password
Error message
Empty Password
What it means
BindAuthenticator.authenticate() refuses to perform an LDAP bind when the token's credentials are null or empty, throwing BadCredentialsException('Empty Password'). An empty-password bind is either rejected by the directory or — worse on AD — succeeds as an unauthenticated bind, so the authenticator blocks it explicitly.
Source
Thrown at ldap/src/main/java/org/springframework/security/ldap/authentication/BindAuthenticator.java:72
* Create an initialized instance using the {@link BaseLdapPathContextSource}
* provided.
* @param contextSource the BaseLdapPathContextSource instance against which bind
* operations will be performed.
*/
public BindAuthenticator(BaseLdapPathContextSource contextSource) {
super(contextSource);
}
@Override
public DirContextOperations authenticate(Authentication authentication) {
DirContextOperations user = null;
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
"Can only process UsernamePasswordAuthenticationToken objects");
String username = authentication.getName();
String password = (String) authentication.getCredentials();
if (!StringUtils.hasLength(password)) {
logger.debug(LogMessage.format("Failed to authenticate since no credentials provided"));
throw new BadCredentialsException(
this.messages.getMessage("BindAuthenticator.emptyPassword", "Empty Password"));
}
// If DN patterns are configured, try authenticating with them directly
for (String dn : getUserDns(username)) {
user = bindWithDn(dn, username, password);
if (user != null) {
break;
}
}
if (user == null) {
logger.debug(LogMessage.of(() -> "Failed to bind with any user DNs " + getUserDns(username)));
}
// Otherwise use the configured search object to find the user and authenticate
// with the returned DN.
if (user == null && getUserSearch() != null) {
logger.trace("Searching for user using " + getUserSearch());
DirContextOperations userFromSearch = getUserSearch().searchForUser(username);
user = bindWithDn(userFromSearch.getDn().toString(), username, password, userFromSearch.getAttributes());View on GitHub (pinned to 96852e8860)
Solutions
- Reject empty passwords at the edge (controller/filter) before reaching the AuthenticationManager.
- Fix field-name mismatches between the client payload and your DTO so the password is actually populated.
- If username/password were swapped in the token constructor, correct the argument order.
- Log a debug message and return a generic 400 to avoid revealing which field was empty.
Example fix
// before
Authentication auth = new UsernamePasswordAuthenticationToken(username, null);
authManager.authenticate(auth); // Empty Password from BindAuthenticator
// after
if (password == null || password.isEmpty()) {
throw new BadCredentialsException("credentials required");
}
Authentication auth = new UsernamePasswordAuthenticationToken(username, password);
authManager.authenticate(auth); Defensive patterns
Strategy: validation
Validate before calling
if (!(authentication.getCredentials() instanceof String pwd) || pwd.isEmpty()) {
throw new BadCredentialsException("credentials required");
} Type guard
static boolean bindable(UsernamePasswordAuthenticationToken t) {
return t.getCredentials() instanceof String s && !s.isEmpty();
} Try / catch
try {
return bindAuthenticator.authenticate(token);
} catch (BadCredentialsException e) {
logger.debug("bind rejected: {}", e.getMessage());
throw new AuthenticationCredentialsNotFoundException("provide username and password");
} Prevention
- Check token constructor argument order so credentials are not null.
- Reject empty passwords in filters/controllers before the provider.
- Log BindAuthenticator debug messages to see the empty-password path.
- Never allow anonymous/empty binds through your login flow.
When it happens
Trigger: Calling LdapAuthenticationProvider/BindAuthenticator.authenticate() with a UsernamePasswordAuthenticationToken whose cast (String) authentication.getCredentials() is null or "" — empty login form password, missing JSON field, or token built without credentials.
Common situations: REST clients omitting the password property, scripts hitting the login endpoint with only a username, misconfigured serializers dropping null fields, or username/password swapped so credentials ended up empty.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Empty Password
- Bad credentials
- <namingException.getMessage()>
- Empty Username
- ${ex.getStatus().getDefaultMessage()}
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/ecb9104284721e1c.
Report an issue: GitHub.