Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom validation before login action with spring security?

I'm new to spring so not fully aware of how the UserDetailsService works.

What I would like is for my login form to act the same way my signup form does. However, instead, when sending a post request using login details the UserDetailsService class seems to execute first. Can someone explain how the UserDetailsService works (i.e. when its called) and how I can change my security config to execute whats in my controller POST method for login (as it does for signup).

Controller:

@Controller
public class controller{

@RequestMapping(value = "/signup", method = RequestMethod.POST)
public String registration(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
    LOG.debug("Signing up with user: {}", userForm);

    signUpValidationService.validate(userForm, bindingResult);

    if (bindingResult.hasErrors()) {
        return "login/Signup";
    }

    userService.saveUser(userForm);
    userService.autologin(userForm.getEmail(), userForm.getPassword());

    return "about/Home";
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute("userForm") final User userForm, final BindingResult bindingResult) {
    LOG.debug("Logging in with user: {}", userForm);

    loginValidationService.validate(userForm, bindingResult);

    if (bindingResult.hasErrors()) {
        return "login/Login";
    }

    userService.autologin(userForm.getEmail(), userForm.getPassword());

    LOG.debug("Successfully logged in with user: {}", userForm.getFirstName());

    return "about/Home";
}

}

My security config:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter {

/**
 * {@inheritDoc}
 */
@Override
protected void configure(HttpSecurity http) throws Exception {

    http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/resources/**", "/signup", "/", "/home", "/about")
            .permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .successHandler(successHandler())
            .permitAll()
            .and()
            .logout().deleteCookies("JSESSIONID")
            .logoutUrl("/logout")
            .logoutSuccessUrl("/home")
            .permitAll()
            .and()
            .rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400)
            .and()
            .sessionManagement()
            .sessionFixation().migrateSession()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            .invalidSessionUrl("/invalid_session")
            .maximumSessions(2)
            .expiredUrl("/expired_session");
}

/**
 * User login validation configuration.
 *
 * @param auth
 *         {@link AuthenticationManagerBuilder}
 * @param userDetailsService
 *         {@link UserDetailsService}
 * @throws Exception
 *         {@link Exception}
 */
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth, final UserDetailsService userDetailsService)
        throws
        Exception {
    auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(new BCryptPasswordEncoder());
}

/**
 * Handles login success configuration policy.
 *
 * @return {@link AuthenticationSuccessHandler}
 */
private final AuthenticationSuccessHandler successHandler() {
    return new UrlAuthenticationSuccessHandler();
}

/**
 * Sets security evaluation context.
 *
 * @return {@link SecurityEvaluationContextExtension}
 */
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
    return new SecurityEvaluationContextExtension();
}
}

1 Answers

Spring security auto detect your yourOwnuserDetailsService wich implemented UserDetailsService and when user enters their username and password into a login screen and clicks a login button. The entered information is placed into an object called Authentication which is passed to the AuthenticationManager’s authenticate method. this method will loop through all AuthenticationProviders that are configured and calls their authenticate method, passing in the Authentication object. Each AuthenticationProvider will calls its configured UserDetailsService’s loadUserByUserName method.

you don't need to call it explicitly, spring security will take care of it if you need if you need catch Spring Security login form before Spring security catch it, here is details

You can do this using regular Spring Security functionality. The steps are:

Implement a custom WebAuthenticationDetailsSource and WebAuthenticationDetails. The WebAuthenticationDetails will capture the extra form fields that you want to validate.

Note: In Spring 3.0 you'll need to use a BeanPostProcessor to configure the WebAuthenticationDetailsSource into the UsernamePasswordAuthenticationFilter. In Spring 3.1 you can do this directly in the namespace config.

Implement a custom AuthenticationProvider and in authenticate() check the WebAuthenticationDetails, throwing a AuthenticationException if validation fails. In your login page check for this exception.

Alternatively, you can create a Filter that does your validation and add it before the Spring Security filter.

Also if you want validate parameters then you can check it with extends UsernamePasswordAuthenticationFilter

 public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

       //your logic
        return super.attemptAuthentication(request, response); 
    } 
like image 60
Bhushan Uniyal Avatar answered Jan 23 '26 15:01

Bhushan Uniyal