Custom failureHandler throws 401 in Spring security login

Viewed 142

I'm working on a custom login failureHandler in my app, and I noticed that if I type anyRequest().authenticated() in authorizeRequest() everything works, but I have no CSS on my login page, but if I type anyRequest().permitAll(), I have CSS on my site, and logging with wrong credentials throws 401 - unauthorized error. It only happens in my custom failureHandler. Can you tell me why it happens?

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/admin/**")
                .hasRole("ADMIN")
            .antMatchers("/user/**")
                .hasAnyRole("USER", "ADMIN")
            .antMatchers("/guest*")
                .permitAll()
            .anyRequest()
                .permitAll()
//          .anyRequest()
//              .authenticated()
            .and()
        .formLogin()
            .loginPage("/guest/login")
            .permitAll()
            .defaultSuccessUrl("/user/all-tasks", true)
            .failureUrl("/guest/login")
            .failureHandler(new MyAuthenticationFailureHandler())
            .and()
        .logout()
            .logoutUrl("/user/logout")
            .deleteCookies("JSESSIONID")
            .and()
        .cors()
            .and()
        .csrf()
            .disable();
}
@Component
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        super.onAuthenticationFailure(request, response, exception);
        request.getSession().setAttribute("error", true);
    }
}
1 Answers

logging with wrong credentials throws 401 - unauthorized error

Because you are doing :

.failureUrl("/guest/login")
.failureHandler(new MyAuthenticationFailureHandler())

and what are done by failureUrl() will be reset by the subsequent failureHandler().So the customised SimpleUrlAuthenticationFailureHandler do not configure with failureUrl yet and hence it will send 401 if the authentication fails since it does know which URL to redirect to.Change it to :

.failureHandler(new MyAuthenticationFailureHandler("/guest/login")) 

should redirect to "/guest/login" if authentication fails.

I noticed that if I type anyRequest().authenticated() in authorizeRequest() everything works, but I have no CSS on my login page, but if I type anyRequest().permitAll(), I have CSS on my site,

Because in case of anyRequest().authenticated() , the CSS 's URL also required an authenticated user to access. But in login page , the user must not be authenticated. Because if they are authenticated , it does not make sense that they can go to login page.So no CSS will be shown in login page since only unauthenticated users can go to it.

You have to exclude all the related url resources required by login page to work from any protections by configuring WebSecurity. Everyone should access them :

public void configure(WebSecurity web) throws Exception {
    web.ignoring()
       .antMatchers("/css/**")
       .antMatchers("/anyThingRequiredByLoginPageToWork/**");
}
Related