Configure authentication error response in Spring Security using AuthenticationFailureHandler

Currently, when the user fails authentication, spring responds:

{"error": "invalid_grant","error_description": "Bad credentials"}

And I would like to improve this answer with a response code, for example:

{"responsecode": "XYZ","error": "invalid_grant","error_description": "Bad credentials"}

After someone gets bored, it looks like I need to do this, is to implement the AuthenticationFailureHandler, which I started to do. However, the onAuthenticationFailure method never appears when I send the wrong credentials. I went through the code and put the input in the onAuthenticationFailure method to confirm that it has not been reached.

My error handler:

@Component
public class SSOAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException {
        super.onAuthenticationFailure(request, response, exception);
        response.addHeader("responsecode", "XYZ");  
    }
}

And my WebSecurityConfigurerAdapter adapter contains:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired SSOAuthenticationFailureHandler authenticationFailureHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.formLogin().failureHandler(authenticationFailureHandler);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(service).passwordEncoder(passwordEncoder());
        auth.authenticationEventPublisher(defaultAuthenticationEventPublisher());
    }

    @Bean
    public DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher(){
        return new DefaultAuthenticationEventPublisher();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public SSOAuthenticationFailureHandler authenticationHandlerBean() {
        return new SSOAuthenticationFailureHandler();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }
}

My questions:

  • Is this the right way to achieve the result I want? (Configure spring authentication request)
  • , - , ( onAuthenticationFailure?

!

+4
1

Spring , .exceptionHandling() HttpSecurity configure. , .accessDeniedHandler(accessDeniedHandler()).

, , , @PreAuthorized, @PostAuthorized @Secured.

:

SecurityConfig.java
/* 
   The following two are the classes we're going to create later on.  
   You can autowire them into your Security Configuration class.
*/
@Autowired
private CustomAuthenticationEntryPoint unauthorizedHandler;

@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;    

/*
  Adds exception handling to you HttpSecurity config object.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf()
        .disable()
        .exceptionHandling()
            .authencationEntryPoint(unauthorizedHandler)  // handles bad credentials
            .accessDeniedHandler(accessDeniedHandler);    // You're using the autowired members above.


    http.formLogin().failureHandler(authenticationFailureHandler);
}

/*
  This will be used to create the json we'll send back to the client from
  the CustomAuthenticationEntryPoint class.
*/
@Bean
public Jackson2JsonObjectMapper jackson2JsonObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
    return new Jackson2JsonObjectMapper(mapper);
}   

CustomAuthenticationEntryPoint.java

. . JSON HttpServletResponse. Mapper Jackson bean, .

 @Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

    private static final long serialVersionUID = -8970718410437077606L;

    @Autowired  // the Jackson object mapper bean we created in the config
    private Jackson2JsonObjectMapper jackson2JsonObjectMapper;

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e) throws IOException {

        /* 
          This is a pojo you can create to hold the repsonse code, error, and description.  
          You can create a POJO to hold whatever information you want to send back.
        */ 
        CustomError error = new CustomError(HttpStatus.FORBIDDEN, error, description);

        /*
          Here we're going to creat a json strong from the CustomError object we just created.
          We set the media type, encoding, and then get the write from the response object and write
      our json string to the response.
        */
        try {
            String json = jackson2JsonObjectMapper.toJson(error);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
            response.getWriter().write(json);
        } catch (Exception e1) {
            e1.printStackTrace();
        }

    }
}

CustomAccessDeniedHandler.java

, . , , "bad credentials".

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
        AccessDeniedException e) throws IOException, ServletException {

    // You can create your own repsonse here to handle method level access denied reponses..
    // Follow similar method to the bad credentials handler above.
    }

}

, .

+6

Source: https://habr.com/ru/post/1672488/


All Articles