Spring security

·

13 min read

Note: Whenever the request comes it goes through SecurityFilterChain in spring security


SecurityFilterChain

  • The SecurityFilterChain is a sequence of filters that are applied to incoming HTTP requests in a Spring Security configuration.

  • These filters are arranged in a chain to ensure that different security tasks are handled in the right order for each request.

  • The filters perform various actions such as checking for authentication, verifying permissions, and modifying the request or response. We will see more about this below.

Authentication Filter

  • In Spring Security, the Authentication Filter is a filter responsible for handling the authentication process. It is part of the security filter chain, and its primary role is to authenticate users based on the information provided in the request (e.g., username and password, token, or OAuth credentials).

  • Authentication Filter in Spring Security is responsible for creating an Authentication object. Here's a breakdown of how that works:

Authentication Object Creation Process:

1). Extracting Credentials:

  • When a request is made (for example, a login request), the AuthenticationFilter (e.g., UsernamePasswordAuthenticationFilter) extracts the necessary credentials from the request, such as:

    • Username

    • Password

    • In the case of token-based authentication (like JWT), the filter would extract the token from the request (typically from the Authorization header).

2). Creating the Authentication Object:

  • After extracting the credentials, the filter creates an Authentication object that holds the credentials and any additional data. For example:

    • For username/password authentication, the filter would create a UsernamePasswordAuthenticationToken object:

        Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
      
    • For token-based authentication, it could create a BearerTokenAuthenticationToken object (or a custom authentication token) that holds the token extracted from the request.

3). Delegating to the AuthenticationManager:

  • Once the Authentication object is created (but not yet authenticated), the filter passes it to the AuthenticationManager for authentication.

UsernamePasswordAuthenticationFilter

  • The AuthenticationFilter is a generic, abstract class in Spring Security responsible for handling the authentication process for various types of authentication schemes. It is part of the security filter chain, and its purpose is to intercept requests and initiate the authentication process based on the credentials provided in those requests.

  • While AuthenticationFilter is abstract and doesn't perform authentication itself, it is the base class for more specific authentication filters, such as UsernamePasswordAuthenticationFilter (for username/password authentication), BearerTokenAuthenticationFilter (for JWT or token-based authentication), and others.

  • The UsernamePasswordAuthenticationFilter is a concrete subclass of AuthenticationFilter that handles form-based authentication with a username and password. This is the most commonly used filter for handling login forms in a web application.

  • Authentication Process:

    • It extracts the username and password from the request (usually HttpServletRequest).

    • Creates an UsernamePasswordAuthenticationToken object with these credentials.

    • Passes this token to the AuthenticationManager for authentication.

UsernamePasswordAuthenticationToken

  • UsernamePasswordAuthenticationToken is a specific implementation of the Authentication interface in Spring Security.

  • It is used primarily in username and password authentication scenarios (such as login forms). It represents the credentials (username and password) provided by the user in a login request, as well as the authenticated user's authorities (roles/permissions) once authentication is successful.

Key Characteristics of UsernamePasswordAuthenticationToken:

  1. Implements Authentication Interface:

    • The UsernamePasswordAuthenticationToken implements the Authentication interface, which is a core interface in Spring Security for representing an authentication request and response.

    • The Authentication interface has methods to check if the user is authenticated, get the user's principal (identity), get the user's granted authorities (roles), and more.

  2. Holds Principal and Credentials:

    • Principal: The principal is typically the username of the user (or any other identity).

    • Credentials: The credentials usually hold the password or other authentication token used to verify the user's identity.

  3. Used During Authentication:

    • Before authentication: It is created by the authentication filter (e.g., UsernamePasswordAuthenticationFilter) when the user submits their username and password. At this stage, the credentials (username and password) are not yet verified.

    • After authentication: If the AuthenticationManager successfully authenticates the user, the UsernamePasswordAuthenticationToken is populated with the authenticated user’s details (principal, authorities, etc.) and stored in the SecurityContextHolder.

Example Usage:

When a user submits a login form, the UsernamePasswordAuthenticationFilter creates an instance of UsernamePasswordAuthenticationToken:

Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);

Important Note :

  • That means AuthenticationFilter creates authentication object but in behind there is UsernamePasswordAuthenticationFilter who extracts username and password from request and it creates instance of UsernamePasswordAuthenticationToken which is implementation of Authentication interface eventually we will get Authentication object and it is further passed to AuthenticationManger.

AuthenticationManager Interface

  • The AuthenticationManager is a core interface in Spring Security that is responsible for handling the authentication process. It takes an Authentication object from AuthenticationFilter (containing credentials provided by the user) and validates it. It Actually send’s authentication object to AuthenticationProvider and it validate’s it.

  • Without an AuthenticationManager, Spring Security wouldn't have a clear mechanism to coordinate multiple AuthenticationProviders and manage the authentication process for different types of authentication tokens.

Key Points about AuthenticationManager:

  1. Purpose:

    • The AuthenticationManager acts as a central point for managing authentication.

    • It delegates the actual authentication to one or more AuthenticationProvider implementations.

  2. How it Works:

    • It takes an Authentication object (e.g., UsernamePasswordAuthenticationToken) as input.

    • Validates the credentials using configured AuthenticationProvider instances.

    • If authentication is successful:

      • Returns a new, authenticated Authentication object with principal, authorities, and authenticated = true.
    • If authentication fails:

      • Throws an AuthenticationException (e.g., BadCredentialsException).
  3. Implementation:

    • The most common implementation of AuthenticationManager is ProviderManager.

    • ProviderManager delegates authentication to a list of AuthenticationProvider instances.

ProviderManager Class

  • The most commonly used implementation of AuthenticationManager is ProviderManager. This class is responsible for managing a chain of AuthenticationProvider instances and coordinating the authentication process by delegating the authentication request to the appropriate AuthenticationProvider.

Key Features of ProviderManager

  • It delegates authentication to each AuthenticationProvider until one successfully authenticates the request or all providers fail.

  • If the authentication is successful, it returns an authenticated Authentication object.

  • If no provider can authenticate the request or if there’s an error in the process, it throws an AuthenticationException.

Default Configuration in Spring Security

  • When you configure Spring Security (e.g., in a WebSecurityConfigurerAdapter), Spring Boot automatically provides a ProviderManager as the default AuthenticationManager. You typically don’t need to explicitly define the AuthenticationManager unless you want to customize its behavior.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authenticationManager(authenticationManager())  // Uses the default ProviderManager
            .formLogin()
            .and()
            .authorizeRequests()
            .anyRequest().authenticated();
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();  // This is where ProviderManager is configured by default
    }
}

AuthenticationProvider Interface

  • The AuthenticationProvider interface in Spring Security is responsible for performing the actual authentication logic. It validates an Authentication object, such as a UsernamePasswordAuthenticationToken, against a specific source, like a database or an external system. It works as a plugin to the AuthenticationManager, allowing different types of authentication mechanisms to coexist.

Key Points about AuthenticationProvider

  1. Purpose:

    • The AuthenticationProvider performs the validation of credentials (e.g., username and password) and provides an authenticated Authentication object if successful.
  2. How it Works:

    • The AuthenticationManager delegates authentication requests to one or more AuthenticationProviders in its list.

    • Each AuthenticationProvider checks whether it can handle the type of Authentication object passed to it.

    • If it supports the type, it attempts to authenticate the request.

  3. Primary Methods: The AuthenticationProvider interface defines two methods:

    • Authentication authenticate(Authentication authentication):

      • Validates the Authentication object.

      • Returns an authenticated Authentication object if validation is successful.

      • Throws an AuthenticationException if authentication fails.

    • boolean supports(Class<?> authentication):

      • Indicates whether the AuthenticationProvider can handle the given type of Authentication object.

Common Implementations of AuthenticationProvider

  1. DaoAuthenticationProvider:

    • Used for validating username-password credentials.

    • Relies on a UserDetailsService to fetch user details and a PasswordEncoder to validate the password.

    • Example:

        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
      
  2. JwtAuthenticationProvider:

    • Used for validating JWT tokens in stateless authentication.

    • Custom implementation is often used for token-based authentication.

  3. RememberMeAuthenticationProvider:

    • Used for "Remember Me" functionality.

UserDetailService Interface

  • The UserDetailsService is a core interface in Spring Security responsible for retrieving user-related data. It is used to load user-specific details (such as username, password, and authorities) during the authentication process.

  • When a user tries to authenticate (e.g., logging in), Spring Security needs to fetch the user's information from a persistent store (like a database). This is where UserDetailsService comes into play.

Key Method:

  • loadUserByUsername(String username): This is the most important method in the UserDetailsService interface. It is used to retrieve user details based on the username (or another unique identifier).
public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

The loadUserByUsername method should return a UserDetails object, which represents the user’s information (such as their username, password, authorities, etc.).

PasswordEncoder

  • The PasswordEncoder is an interface in Spring Security used to handle password encoding and matching. It provides methods to hash passwords before saving them to the database and to verify the hashed password during the authentication process.

  • By using a PasswordEncoder, passwords are stored in a secure, irreversible format, preventing plain-text passwords from being stored or leaked.

Summary

  • AuthenticationProvider uses UserDetailsService to load user details (such as the username, password, and roles) from a data source during the authentication process.

  • The AuthenticationProvider checks the credentials and performs authentication, while the UserDetailsService is responsible for fetching the user data, typically from a database.


SecurityContext

  • In Spring Security, the SecurityContext is a container for holding security-related information about the current user (such as their authentication details) throughout the lifespan of a request. It is a central concept for managing security contexts in a web application.

  • Once the fully authenticated object is created by AuthenticationProvider it is passed to AuthenticationManager and then AuthenticationFilter and then AuthenticationFilter stores it in SecurityContext.

Key Points about SecurityContext:

  1. Holds the Current User's Authentication:

    • The SecurityContext holds an Authentication object, which represents the current authenticated user's details, such as:

      • Username: The identifier of the authenticated user.

      • Authorities: The roles or permissions granted to the user.

      • Credentials: Information like passwords (although typically not stored directly).

      • Principal: The user details (can be a UserDetails object, or any other object representing the authenticated user).

  2. SecurityContextHolder:

    • Spring Security uses the SecurityContextHolder class to store and retrieve the SecurityContext.

    • SecurityContextHolder has a static method to access the SecurityContext, allowing you to get or set the Authentication object in a thread-local storage.

  3. Thread-Local Storage:

    • The SecurityContext is typically stored in a thread-local variable, meaning it is specific to the current thread of execution. This allows each request to maintain its own security context, even in a multi-threaded environment (such as web requests handled by different threads).

Key Methods:

  • SecurityContextHolder.getContext(): Retrieves the SecurityContext for the current thread.

  • SecurityContextHolder.getContext().setAuthentication(Authentication authentication): Sets the Authentication object in the current SecurityContext.

  • SecurityContextHolder.clearContext(): Clears the SecurityContext, effectively logging the user out.

Summarization of Flow:

1. Incoming Request (Authentication Filter Triggered):

  • A user sends a request to the application (e.g., login with username and password).

2. AuthenticationFilter (e.g., UsernamePasswordAuthenticationFilter):

  • The AuthenticationFilter (typically UsernamePasswordAuthenticationFilter for login) intercepts the request.

  • It extracts the username and password from the request (e.g., form data, headers, etc.).

  • It then creates an Authentication object (e.g., UsernamePasswordAuthenticationToken) using these credentials:

      Authentication authRequest = new UsernamePasswordAuthenticationToken(username, password);
    
  • The AuthenticationFilter passes the Authentication object to the AuthenticationManager.

3. AuthenticationManager:

  • The AuthenticationManager is responsible for deciding how to authenticate the user.

  • It forwards the Authentication object to one or more AuthenticationProvider instances to validate the credentials.

4. AuthenticationProvider (e.g., DaoAuthenticationProvider):

  • The AuthenticationProvider (such as DaoAuthenticationProvider) validates the credentials.

  • It compares the username and password from the Authentication object with the values stored in the database.

  • If the credentials are valid, the AuthenticationProvider creates an authenticated Authentication object (e.g., UsernamePasswordAuthenticationToken), which contains the principal (user) and authorities (roles or permissions).

5. Return Authenticated Authentication Object:

  • The AuthenticationProvider returns the authenticated Authentication object to the AuthenticationManager.

6. AuthenticationFilter Sets SecurityContext:

  • The AuthenticationFilter receives the authenticated Authentication object.

  • It sets the Authentication object in the SecurityContext using SecurityContextHolder:

      SecurityContextHolder.getContext().setAuthentication(authentication);
    
  • This step ensures that the user's authentication information is available throughout the application for authorization and access control decisions.

7. Request Continues:

  • After authentication, the request is passed to the next filter in the chain, or if it’s a successful login, the response can proceed (e.g., redirecting the user to a dashboard or returning a success response).

Summary of Components Involved:

  • AuthenticationFilter: Intercepts the request, extracts credentials, and initiates the authentication process.

  • AuthenticationManager: Forwards the Authentication object to the appropriate AuthenticationProvider for validation.

  • AuthenticationProvider: Validates the credentials and creates an authenticated Authentication object.

  • SecurityContext: The AuthenticationFilter sets the authenticated Authentication object in the SecurityContext for access control and further processing.


What is SecurityFilterChain

  • In Spring Security, the SecurityFilterChain defines a series of filters that are applied to HTTP requests as they pass through the security pipeline. Each filter serves a specific purpose and is applied in a sequence, depending on the configuration.

  • The filters in the SecurityFilterChain typically handle different aspects of security, such as authentication, authorization, session management, and protection against common vulnerabilities (e.g., CSRF, CORS).

What is difference between AuthenticationFilter and SecurityFilterChain

  • AuthenticationFilter is one of the filters used by the SecurityFilterChain to process requests, and the SecurityFilterChain is the overall configuration that manages the sequence and application of various security filters.

Common Filters in SecurityFilterChain

  1. ChannelProcessingFilter:

    • This filter is used to ensure that requests are served over a secure channel (e.g., HTTPS). If a request comes over HTTP but should be served over HTTPS, this filter can redirect the request to the secure channel.

    • It’s usually the first filter applied in the chain.

  2. SecurityContextPersistenceFilter:

    • This filter loads the SecurityContext (which contains the authentication information) from the session or other persistent storage (e.g., cookies).

    • It is responsible for managing the SecurityContext between requests.

  3. AuthenticationFilter (e.g., UsernamePasswordAuthenticationFilter):

    • This filter handles authentication logic. For example, the UsernamePasswordAuthenticationFilter checks for the presence of a username and password, and if found, tries to authenticate the user by delegating the authentication task to an AuthenticationManager.

    • If using other authentication mechanisms like JWT, a custom AuthenticationFilter (e.g., JwtAuthenticationFilter) could be used.

  4. CsrfFilter:

    • This filter provides protection against Cross-Site Request Forgery (CSRF) attacks. It ensures that requests made to the server include a valid CSRF token, making it harder for attackers to trick users into submitting malicious requests on their behalf.
  5. CorsFilter:

    • This filter handles Cross-Origin Resource Sharing (CORS) requests. It adds the necessary HTTP headers to support cross-origin requests, often required for APIs that are accessed by web applications hosted on different domains.
  • There are many more filters in the SecurityChainFilter

Does a Request Pass Through All Filters in the SecurityFilterChain?

  • Yes, a request typically passes through each filter in the SecurityFilterChain, but not all filters will necessarily take action on every request.

  • Filters are applied in the order they are defined, and each one serves a distinct purpose in securing the application.

Example of how SecurityFilterChain is defined in security configuration


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

        // this line specifies that, each request comming to server is authenticated
        http.authorizeHttpRequests().anyRequest().authenticated(); 

        http.formLogin(Customizer.withDefaults());
        http.httpBasic(Customizer.withDefaults());
        return (SecurityFilterChain)http.build();
    }

}

Important Note:

  • By default Spring security framework protects all the paths present inside the web application.This behaviour is due to code present inside the method defaultSecurityFilterChain(HttpSecurity http) of class SpringBootWebSecurityConfiguration

  • The class WebSecurityConfigurerAdapter→configure(HttpSecurity http) is deprecated so do not use.

   @Bean
   SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
      http.authorizeRequests().anyRequest().authenticated();
      http.formLogin();
      http.httpBasic();
      return http.build();
   }

In memory authentication

  • You can use In memory authentication for testing purpose lets say you don’t want to create user from database you can use in memory authentication.

Example:

  • SecurityConfig.java
package org.example.springsecuritypractice.config;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    UserDetailsService userDetailsService() {
        UserDetails user1 = User.withUsername("harsh")
                .password("{noop}harsh")
                .roles("USER")
                .build();

        UserDetails user2 = User.withUsername("prachi")
                .password("{noop}harsh")
                .roles("ADMIN")
                .build();

        return new InMemoryUserDetailsManager(user1, user2);
    }
}

Roles and PreAuthrorize in Spring security

What is @PreAuthorize?

  • The @PreAuthorize annotation in Spring Security is used to perform method-level security. It allows you to apply access control on individual methods based on specified security conditions, such as user roles, authorities, or custom expressions.

Common Usage

  1. Role-Based Access Control

     @PreAuthorize("hasRole('ADMIN')")
     public void adminOnlyMethod() {
         // Only accessible by users with the ADMIN role
     }
    
  2. Authority-Based Access Control

     @PreAuthorize("hasAuthority('READ_PRIVILEGE')")
     public void readOnlyMethod() {
         // Only accessible by users with the READ_PRIVILEGE authority
     }
    
  3. Multiple Roles or Authorities

     @PreAuthorize("hasAnyRole('ADMIN', 'USER')")
     public void adminOrUserMethod() {
     }
    

What is @EnableMethodSecurity?

The @EnableMethodSecurity annotation is used to enable method-level security in a Spring Security configuration class. Without this annotation, annotations like @PreAuthorize, @PostAuthorize, and others related to method security will not work.