{"record":{"id":"b46184bcd5516d18","repo":"spring-projects/spring-security","slug":"bad-credentials-b46184","errorCode":null,"errorMessage":"Bad credentials","messagePattern":"Bad credentials","errorType":"exception","errorClass":"BadCredentialsException","httpStatus":null,"severity":"error","filePath":"ldap/src/main/java/org/springframework/security/ldap/authentication/LdapAuthenticationProvider.java","lineNumber":184,"sourceCode":"\n\tpublic void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {\n\t\tthis.hideUserNotFoundExceptions = hideUserNotFoundExceptions;\n\t}\n\n\t@Override\n\tprotected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken authentication) {\n\t\ttry {\n\t\t\treturn getAuthenticator().authenticate(authentication);\n\t\t}\n\t\tcatch (PasswordPolicyException ex) {\n\t\t\t// The only reason a ppolicy exception can occur during a bind is that the\n\t\t\t// account is locked.\n\t\t\tthrow new LockedException(\n\t\t\t\t\tthis.messages.getMessage(ex.getStatus().getErrorCode(), ex.getStatus().getDefaultMessage()));\n\t\t}\n\t\tcatch (UsernameNotFoundException ex) {\n\t\t\tif (this.hideUserNotFoundExceptions) {\n\t\t\t\tthrow new BadCredentialsException(\n\t\t\t\t\t\tthis.messages.getMessage(\"LdapAuthenticationProvider.badCredentials\", \"Bad credentials\"));\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (NamingException ex) {\n\t\t\tthrow new InternalAuthenticationServiceException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected Collection<? extends GrantedAuthority> loadUserAuthorities(DirContextOperations userData, String username,\n\t\t\tString password) {\n\t\treturn getAuthoritiesPopulator().getGrantedAuthorities(userData, username);\n\t}\n\n}\n","sourceCodeStart":166,"sourceCodeEnd":201,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/ldap/src/main/java/org/springframework/security/ldap/authentication/LdapAuthenticationProvider.java#L166-L201","documentation":"LdapAuthenticationProvider.doAuthentication() catches UsernameNotFoundException from the authenticator and, when hideUserNotFoundExceptions is true (the default), masks it as BadCredentialsException('Bad credentials') to avoid revealing which usernames exist. When hideUserNotFoundExceptions is false the original UsernameNotFoundException is rethrown.","triggerScenarios":"The configured UserSearch/LdapUserSearch finds no directory entry matching the submitted username (or the bind DN lookup fails) and doAuthentication translates the resulting UsernameNotFoundException into this BadCredentialsException unless user-not-found exceptions are not hidden.","commonSituations":"Typo'd username, wrong userSearchBase or filter so existing users are never found, users in an OU not covered by the search, casing/base DN mismatch after a directory migration, or testing account-enumeration protection.","solutions":["Verify userSearchBase and the search filter (e.g. (uid={0}) vs (sAMAccountName={0})) match the directory schema and actually locate the user (test with ldapsearch).","Check the search uses the correct base DN and that the context source's manager credentials allow reading the user subtree.","Remember 'Bad credentials' here can mean 'user not found' — don't debug only the password path.","For debugging only, set hideUserNotFoundExceptions(false) temporarily to surface the real UsernameNotFoundException.","Confirm users are synced/present in the directory the app points to (not a staging vs prod mismatch)."],"exampleFix":"// before\nprovider.setHideUserNotFoundExceptions(false); // leaks user existence in prod\n\n// after\n// prod: keep masking (default true)\nprovider.setHideUserNotFoundExceptions(true);\n// fix lookup instead:\nLdapUserSearch search = new FilterBasedLdapUserSearch(\"ou=people\", \"(sAMAccountName={0})\", contextSource);\nprovider.setUserSearch(search);","handlingStrategy":"try-catch","validationCode":"// verify user resolves before authenticating\nLdapTemplate ldap = new LdapTemplate(contextSource);\nboolean exists = !ldap.search(\"ou=people\", \"(sAMAccountName={0})\",\n        new String[] { username }, new AbstractContextMapper<Object>() {\n            protected Object doMapFromContext(DirContextOperations c) { return new Object(); }\n        }).isEmpty();\nif (!exists) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, \"invalid username or password\");","typeGuard":null,"tryCatchPattern":"try {\n    return authManager.authenticate(token);\n} catch (BadCredentialsException e) {\n    // can mean wrong password OR unknown user (hidden) — do not distinguish to clients\n    logger.debug(\"ldap auth failed for {}\", token.getName());\n    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, \"invalid username or password\");\n} catch (UsernameNotFoundException e) {\n    // only reachable when hideUserNotFoundExceptions=false\n    throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, \"invalid username or password\");\n}","preventionTips":["Validate userSearchBase/filter with ldapsearch; most 'Bad credentials' here are lookup misconfigurations.","Keep hideUserNotFoundExceptions=true in production to prevent account enumeration.","Temporarily set it false in dev to see the real UsernameNotFoundException.","Confirm user provisioning/sync so expected accounts exist in the target directory."],"tags":["ldap","user-not-found","bad-credentials","authentication"],"backgroundTag":"user-not-found","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"}