9

Using Spring Security 4.0.2.RELEASE

For basic user authentication using spring-security framework, I implemented spring-security DaoAuthenticationProvider

When user tries to login with correct username, incorrect password and user's account is already locked, then i expected that spring-security authentication module would be throwing BadCredentialsException But instead it throws LockedException

My Questions are

  1. why spring-security is processing the user for further authentication while the credentials specially password is incorrect ?
  2. Is it good practice to show message in application that "User is Locked" even if the password for the user is invalid ?
  3. How do i manage to generate/catch BadCredentialsException for invalid password and locked user ?

Any help would be appreciated. Authentication Provider implementation code is

@Component("authenticationProvider")
public class LoginAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    UserDAO userDAO;

    @Autowired
    @Qualifier("userDetailsService")
    @Override
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        super.setUserDetailsService(userDetailsService);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            Authentication auth = super.authenticate(authentication);
            // if reach here, means login success, else exception will be thrown

            // reset the user attempts
            userDAO.resetPasswordRetryAttempts(authentication.getName());

            return auth;
        } catch (BadCredentialsException ex) {
            // invalid login, update user attempts
            userDAO.updatePasswordRetryAttempts(authentication.getName(), PropertyUtils.getLoginAttemptsLimit());
            throw ex;
        } catch (LockedException ex) {
            // this user is locked
            throw ex;
        } catch (AccountExpiredException ex) {
            // this user is expired
            throw ex;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }

}
Waseem Akhtar
  • 153
  • 1
  • 1
  • 12

2 Answers2

12

You asked:

Spring Security : LockedException is thrown instead of BadCredentialsException, why?

It is because spring security will first check that the account exist and is valid, and after that it checks the password.

More concrete: it is done in AbstractUserDetailsAuthenticationProvider.authenticate. In an very brief description the method works this way:

user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
...
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
...
postAuthenticationChecks.check(user);
  • retrieveUser - load the user
  • preAuthenticationChecks.check(user); - DefaultPreAuthenticationChecks: check for locked...
  • additionalAuthenticationChecks - checks the password
  • postAuthenticationChecks.check(user); - DefaultPostAuthenticationChecks check for not expired credentials

The good point is, that preAuthenticationChecks and postAuthenticationChecks are references to the Interface UserDetailsChecker so you can change them. Just implement your own two UserDetailsChecker, the one Null-Implementation for pre, and one for post that checks everything:

  • !user.isAccountNonLocked()
  • !user.isEnabled()
  • !user.isAccountNonExpired()
  • !user.isCredentialsNonExpired()
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • Well that was something i didn't know about spring-security. Just one more thing, in practical situation would that be alright if we tell the user that the account is locked, even with wrong password, who is trying to authenticate ??? – Waseem Akhtar Nov 28 '15 at 15:43
  • 1
    @Waseem Akhtar: I am not in the position to justify your second question: "Is it good practice...", but IMHO you are right. -- Anyway the good thing of Spring (security) is, that you just need to have a look at the code to answer such question like yours, that is at least the way I did. – Ralph Nov 28 '15 at 16:52
  • also check this answer here https://stackoverflow.com/a/56202422/1533783 – Khalid Habib Sep 04 '19 at 10:35
0

I got this exception when there are more than one user with the same credential (name , email etc.) it the database. It was a test anyway. After I deleted those duplications everything's ok.

Oliver Lu
  • 21
  • 1
  • 2