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

  1. Reject empty passwords at the edge (controller/filter) before reaching the AuthenticationManager.
  2. Fix field-name mismatches between the client payload and your DTO so the password is actually populated.
  3. If username/password were swapped in the token constructor, correct the argument order.
  4. 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

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


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