spring-projects/spring-security · error · InternalAuthenticationServiceException

Bad credentials

Error message

Bad credentials

What it means

ActiveDirectoryLdapAuthenticationProvider.doAuthentication() failed to search for the user after binding, because a NamingException occurred; it logs 'Failed to locate directory entry' and converts the failure to a generic BadCredentialsException with 'Bad credentials' as the message.

Source

Thrown at ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java:183

	public ActiveDirectoryLdapAuthenticationProvider(String domain, String url) {
		Assert.isTrue(StringUtils.hasText(url), "Url cannot be empty");
		this.domain = StringUtils.hasText(domain) ? domain.toLowerCase(Locale.ROOT) : null;
		this.url = url;
		this.rootDn = (this.domain != null) ? rootDnFromDomain(this.domain) : null;
	}

	@Override
	protected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken auth) {
		String username = auth.getName();
		String password = (String) auth.getCredentials();
		Assert.notNull(password, "password cannot be null");
		DirContext ctx = null;
		try {
			ctx = bindAsUser(username, password);
			return searchForUser(ctx, username);
		}
		catch (CommunicationException ex) {
			throw badLdapConnection(ex);
		}
		catch (NamingException ex) {
			this.logger.error("Failed to locate directory entry for authenticated user: " + username, ex);
			throw badCredentials(ex);
		}
		finally {
			LdapUtils.closeContext(ctx);
		}
	}

	/**
	 * Creates the user authority list from the values of the {@code memberOf} attribute
	 * obtained from the user's Active Directory entry.
	 */
	@Override
	protected Collection<? extends GrantedAuthority> loadUserAuthorities(DirContextOperations userData, String username,
			String password) {
		return this.authoritiesPopulator.getGrantedAuthorities(userData, username);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Log/inspect the cause (ex.getCause() is the NamingException) and fix the searchBase or searchFilter so the user DN is resolvable
  2. Enable debug logging for org.springframework.security.ldap to see the failing search
  3. Verify the user exists under the configured base and the domain matches the configured rootDn

Example fix

// before
.ad().domain("corp.example.com").userSearchFilter("(cn={1})") // cn used, users keyed by sAMAccountName
// after
.ad().domain("corp.example.com").userSearchFilter("(sAMAccountName={0})")
Defensive patterns

Strategy: try-catch

Try / catch

try {
    authenticationManager.authenticate(adToken);
} catch (BadCredentialsException e) {
    Throwable cause = e.getCause(); // NamingException from searchForUser
    logger.error("AD lookup failed; check searchBase/searchFilter", cause);
}

Prevention

When it happens

Trigger: bindAsUser succeeded but searchForUser threw NamingException (e.g. user DN not found under configured searchBase, search filter mismatch, directory referral issues) — the underlying cause is the wrapped NamingException.

Common situations: Wrong searchFilter/searchBase configuration so the authenticated user's DN is not found; user exists in a different AD domain than the search base; transient directory errors surfaced as credentials error.

Related errors


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