Spring Security Custom AuthenticationFailureHandler

1. Overview

In this quick tutorial, we’re going to illustrate how to customize Spring Security’sauthentication failures handling in a Spring Boot application. The goal is to authenticate users using a form login approach.

For an introduction to Spring Security and Form Login in Spring Boot, please refer to this and this article, respectively.

2. Authentication and Authorization

Authentication and Authorization are often used in conjunction because they play an essential, and equally important, role when it comes to granting access to the system.

However, they have different meanings and apply different constraints when validating a request:

  • Authentication – precedes Authorization; it’s about validating the received credentials; it’s where we verify that both username and password match the ones that our application recognizes
  • Authorization it’s about verifying if the successfully authenticated user has permissions to access a certain functionality of the application

We can customize both authentication and authorization failures handling, however, in this application, we’re going to focus on authentication failures.

3. Spring Security’s AuthenticationFailureHandler

Spring Security provides a component that handles authentication failures for us by default.

However, it’s not uncommon to find ourselves in a scenario where the default behavior isn’t enough to meet requirements.

If that is the case, we can create our own component and provide the custom behavior we want by implementing the AuthenticationFailureHandler interface:

public class CustomAuthenticationFailureHandler 
  implements AuthenticationFailureHandler {
 
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void onAuthenticationFailure(
      HttpServletRequest request,
      HttpServletResponse response,
      AuthenticationException exception) 
      throws IOException, ServletException {
 
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        Map<String, Object> data = new HashMap<>();
        data.put(
          "timestamp", 
          Calendar.getInstance().getTime());
        data.put(
          "exception", 
          exception.getMessage());

        response.getOutputStream()
          .println(objectMapper.writeValueAsString(data));
    }
}

By default, Spring redirects the user back to the login page with a request parameter containing information about the error.

In this application, we’ll return a 401 response that contains information about the error, as well as the timestamp of its occurrence.

Besides the default component, Spring has others ready to use components that we can leverage depending on what we want to do:

  • DelegatingAuthenticationFailureHandler delegates AuthenticationException subclasses to different AuthenticationFailureHandlers, meaning we can create different behaviors for different instances of AuthenticationException
  • ExceptionMappingAuthenticationFailureHandler redirects the user to a specific URL depending on the AuthenticationException’s full class name
  • ForwardAuthenticationFailureHandler will forward the user to the specified URL regardless of the type of the AuthenticationException
  • SimpleUrlAuthenticationFailureHandler is the component that is used by default, it will redirect the user to a failureUrl, if specified; otherwise, it will simply return a 401 response

Now that we have created our custom AuthenticationFailureHandler, let’s configure our application and override Spring’s default handler:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password(passwordEncoder.encode("user1Pass")).roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) 
      throws Exception {
        http
          .authorizeRequests()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin()
          .failureHandler(authenticationFailureHandler());
    }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Note the failureHandler() call – it’s where we can tell Spring to use our custom component instead of using the default one.

4. Conclusion

In this example, we customized our application’s authentication failure handler leveraging Spring’s AuthenticationFailureHandler interface.

The implementation of this example can be found in the Github project.

When running locally, you can access and test the application at localhost:8080

Related posts:

Inheritance with Jackson
Spring Autowiring of Generic Types
Template Engines for Spring
How to Read a Large File Efficiently with Java
Java Program to Remove the Edges in a Given Cyclic Graph such that its Linear Extension can be Found
Java Program to Implement Sorted Vector
Java Program to Encode a Message Using Playfair Cipher
Java Program to Solve Set Cover Problem assuming at max 2 Elements in a Subset
Mix plain text and HTML content in a mail
Java Program to Implement Gabow Algorithm
Guide to the Synchronized Keyword in Java
Spring Boot: Customize Whitelabel Error Page
Làm thế nào tạo instance của một class mà không gọi từ khóa new?
Set Interface trong Java
Java Program to Search Number Using Divide and Conquer with the Aid of Fibonacci Numbers
Guava Collections Cookbook
Java Program to Generate Random Numbers Using Middle Square Method
Java Program to Implement Euler Circuit Problem
Collect a Java Stream to an Immutable Collection
An Intro to Spring Cloud Task
Java Program to Use Dynamic Programming to Solve Approximate String Matching
Spring Webflux and CORS
The Registration API becomes RESTful
Getting Started with Stream Processing with Spring Cloud Data Flow
Receive email using POP3
Java Program to Solve any Linear Equation in One Variable
Java Program to Use the Bellman-Ford Algorithm to Find the Shortest Path
Vòng lặp for, while, do-while trong Java
Java Program to Implement Brent Cycle Algorithm
Introduction to Java Serialization
Java Web Services – JAX-WS – SOAP
Debugging Reactive Streams in Java