Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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;
        }
    }

}
like image 503
Waseem Akhtar Avatar asked Nov 28 '15 09:11

Waseem Akhtar


People also ask

Which mechanism is used by Spring Security?

Because Spring Security tightly integrates with the Spring Framework and other commonly used authentication mechanisms, such as HTTP basic authentication, X. 509 certificate, form-based login, and so on, it has comprehensive support for both Web applications as well as method-level security.

What is the default username for Spring Security?

As of Spring Security version 5.7. 1, the default username is user and the password is randomly generated and displayed in the console (e.g. 8e557245-73e2-4286-969a-ff57fe326336 ). Ryan H. Ryan H.

What is the use of Websecurityconfigureradapter in spring boot?

Used by the default implementation of authenticationManager() to attempt to obtain an AuthenticationManager . Deprecated. Override this method to configure the HttpSecurity .

Will Spring Security secures all the applications?

If Spring Security is on the classpath, Spring Boot automatically secures all HTTP endpoints with “basic” authentication. However, you can further customize the security settings. The first thing you need to do is add Spring Security to the classpath.


1 Answers

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()
like image 114
Ralph Avatar answered Sep 22 '22 07:09

Ralph