How UserDetails from UserDetailsService compare data passed via user in html form

858 Views Asked by At

I have:

@Service
public class MyAppUserDetailsService implements UserDetailsService {

@Autowired
private IUserInfoDAO userInfoDAO;

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

    User activeUserInfo                   = userInfoDAO.getActiveUser(userName);
    GrantedAuthority authority            = new SimpleGrantedAuthority(activeUserInfo.getRole());


    String userNameVal                    = activeUserInfo.getUserName();
    String userSurnameVal                 = activeUserInfo.getPassword();

    UserDetails userDetails = new org.springframework.security.core.userdetails.User(userNameVal, userSurnameVal, Arrays.asList(authority));
    return userDetails;
}
}

and:

in security chain I configured:

   .and().formLogin()  //login configuration
                .loginPage("/app/login")
                .loginProcessingUrl("/app-login")
                .usernameParameter("app_username")
                .passwordParameter("app_password")
                .defaultSuccessUrl("/app/secure/projects-details")

How user password fill in the form is compare to UserDetails set in loadUserByUsername method?

1

There are 1 best solutions below

1
On

Once you tell the Spring Security Configuration that you will use a particular UserDetailsService or only one @Service bean is an implementation of that interface, then Spring starts using it to fetch the user by username from your persistent storage. Let's simplify the flow:

  1. The user submits a form where fields with names app_username and app_password are present (as configured in Web Security Config) to the loginPage(String) route

  2. The form submission is intercepted by the Spring Security's Filter Chain and Spring is aware that the username is in the field app_username and the password is in the field app_password

  3. The configured UserDetailsService bean is now activated, at its loadUserByUsername(String) method is invoked and the value of app_username field is passed (e.g. john_smith)

  4. As the loadUserByUsername(String) method is by contract designed to return an implementation of UserDetails it always returns an object which contains getUsername() and getPassword() methods

  5. Spring then uses the getPassword() method from the contract and compares the password with app_password field (e.g. super_s3cr3t_password)

  6. If passwordEncoder() is configured in the Spring Security Config or an implementation of PasswordEncoder interface is registered as bean, then spring uses the isPasswordValid(String, String, Object) method to verify the contents of app_password field and the result of UserDetails.getPassword() method

  7. If the UserDetailsService does not throw UsernameNotFoundException and the fetched UserDetails's getPassword() matches the app_password the filter chain continues executing the other filters, otherwise it prevents the user from logging into the application

If a code example simplifies it better, then imagine the following pseudo-java-code:

String usernameField = this.getConfiguredUsernameParameter(); // app_username
String passwordField = this.getConfiguredPasswordParameter(); // app_password
UserDetails userDetails = this.registeredUserDetailsImplementation.loadUserByUsername(request.getParameter(usernameField));
String passwordHash = userDetails.getPassword();
String rawPassword = request.getParameter(passwordField);
String salt = this.getConfiguredSalt(); // can be null
if (this.configuredPasswordEncoder.isPasswordValid(passwordHash, rawPassword, salt) {
   return true;
}

return false;

Keep in mind this is not the Spring Security Code behind the scenes, but just a simplified code illustration of the explanation.