Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security returns String as principal instead of UserDetails on failed login?

Either I'm missing something, or this is how it works...
Namely, I implemented UserDetailsService, and sub-classed (AppUser below) spring utility class User, (that implements UserDetails). If it matters, it goes something like this:

@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
    // try loading user by its name
    SystemUser user = null;
    try {
        user = this.sysUserService.getByUsername(username);
        if(user == null)
            throw new UsernameNotFoundException("User not found!");
    }
    catch(Exception e) {
        throw new DataRetrievalFailureException(
                "Could not load user with username: " + username);
    }
    // load user rights, and create UserDetails instance
    UserDetails res = new AppUser(user, getUserAuthorities(user));

    return res;
}

Then I tried to implement account locking using this approach:

public class LoginFailureEventListenter implements
ApplicationListener<AuthenticationFailureBadCredentialsEvent> {

// rest omitted for brevity

@Override
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
    // ...

    SystemUser user = ((AppUser)event.getAuthentication().getPrincipal()).getSystemUser();
    // cast exception - how is it possible to obtain String 
    // instead of UserDetails object here ?
    // ...
}
}

However, I ran into java.lang.ClassCastException while trying to get the principal object from the supplied event argument (principal object was of type String). I mean, OK - I can just load my SystemUser by username again, to solve the problem, but I did not expect this...
I think that even the source documentation states that getPrincipal() should return UserDetails instance, for this scenario.
Thoughts?

like image 567
Less Avatar asked Jul 03 '13 16:07

Less


1 Answers

Since we are dealing with an authentication failure, the Authentication object in the event is the one which was submitted to the AuthenticationManager (and which was rejected).

In a typical scenario this would be a UsernamePasswordAuthenticationToken where the "principal" property is the submitted username.

The AuthenticationManager supports lots of different authentication mechanisms and, from its perspective, there's no guarantee that a UserDetailsService is even involved in the authentication. All it knows is that the authentication token was not accepted (there was an exception) and it publishes the event accordingly.

Alternative options are to customize the AuthenticationProvider in use or plug in an AuthenticationFailureHandler (if you're using form-login, for example) and do the extra work in there.

like image 111
Shaun the Sheep Avatar answered Nov 15 '22 15:11

Shaun the Sheep