DEV Community

Cover image for Spring security in a nutshell
André Rangel
André Rangel

Posted on

Spring security in a nutshell

As I embarked on my journey of learning Spring and working on small applications, I developed a keen interest in securing them. That's when I came across Spring Security, the go-to framework for safeguarding web apps in the Spring ecosystem, and it's likely the best choice available. With this introductory post, I aim to shed light on the fundamental building blocks of this framework for beginners.

If you start delving into the vast amount of blogs and videos out there about Spring Security, you may feel a little lost due to the overwhelming amount of information. Moreover, some of these resources may contain outdated details due to the framework's frequent updates. That's why it becomes advantageous to gain an understanding of the framework's core components. By grasping how these components interact and function, we can confidently navigate and modify the code to adapt to future updates.

In a broad sense, the purpose of security is to restrict data access to only those who are intended to have it. In practice, security is divided into layers of authentication and authorization, governing requests to endpoints. An application identifies the user through authentication and then determines what actions they are authorized to perform.

The following paragraphs explore the default authentication and authorization actors in depth, unraveling their roles within the framework to give us a hint of what we need to override or customize in order to fulfill our goals.

Default Actors in Spring Security

First, it's important to understand the basics of the underlying agents in the Spring framework. The image below, inspired in [1], provides a concise representation of the Spring MVC workflow.

Spring MVC workflow inspired in [[1]](https://livebook.manning.com/book/spring-security-in-action/welcome/v-7/1).

When a client sends a request to a server, the Dispatcher Servlet redirects the incoming request to the appropriate controller based on its URL path. After the controller is executed, the response is sent back to the client along with a possible view. Ideally, the steps of authentication and authorization are completed before the controller's execution. This is made possible with Servlet Filters [2]. The following image illustrates the stacked filters that handle the HTTP requests before they reach the endpoint.

Stacked Servlet filters before the Servlet, from [[3]](https://docs.spring.io/spring-security/reference/servlet/architecture.html<br>
).

Each filter can be used to prevent the downstream ones from being invoked, to modify the requests and responses used by the downstream filters or the Servlet. Therefore, the security filter instances are located somewhere in the filter queue to manage the authentication and authorization of the requests, and they belong a separate filter chain especially for security purposes (Security Filter Chain).

As shown in the figure, the DelegatingFilterProxy is a filter that acts as a bridge between the Servlet's business and the Spring's configurations. Normally, a Servlet is not aware of Spring defined beans, even more managing them. So, the DelegatingFilterProxy delays the further execution of the dowstream filters and delegates the work to the Spring Bean that implements the filters registered. An important filter is the FilterChainProxy Bean, which has the role to delegate to the many instances in the Security Filter Chain.

In the figure below, inspired in [1], summarizes the entire authentication process. Once the request is intercepted by the authentication filter within the Security Filter Chain, it delegates the authentication responsibility to the AuthenticationManager object, which , in turn, calls the AuthenticationProvider instance responsible for the authentication logic. The UserDetailsService locates the user, validates the password, and returns the result to the authentication filter to store the details in the SecurityContext.

Authentication process according to [[1]](https://livebook.manning.com/book/spring-security-in-action/welcome/v-7/1).

Whenever it is necessary to access data from the current user in the controller, for example, it is possible to retrieve the information through the Authentication object as a method argument in the endpoint.

@GetMapping("/home")
public String home(Authentication auth) {
    String username = auth.getName();
    // do something else.
    return "something";
}

Enter fullscreen mode Exit fullscreen mode

The Authentication object can be obtained from the SecurityContextHolder class as shown below.

SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
Enter fullscreen mode Exit fullscreen mode

These are the default actors. When we place the Spring Security in the path, they work with the default configurations, which means that a basic authentication (username:password) is needed in the header when a request is sent to any endpoint. The username and password are written in the log messages.

User management

First, bear in mind that the framework need to read the users and what they can do. There are two contracts to act in the user management: UserDetailsService and UserDetailsServiceManager. The difference is that the later, UserDetailsServiceManager, extends UserDetailsService to add behaviors that refer to adding, modifying and deleting users.

Both of these contracts get the user's data from UserDetails contract, which is how the user is described to the framework. For example, the following is the UserDetails interface [4] with the minimum to be known by the user.

´´´java
public interface UserDetails extends Serializable {
// User credentials.
String getUsername();
String getPassword();

// Returns actions that the app allows the user to do.
Collection<? extends GrantedAuthority> getAuthorities();

// Enable and disable the account for reasons.
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
´´´

Then, we need a suitable implementation of the UserDetailsService contract to apply the users. This interface is shown below.

public interface UserDetailsService {
   UserDetails loadUserByUsername(String username)
   throws UsernameNotFoundException;
}
Enter fullscreen mode Exit fullscreen mode

As can be seen, this interface has only the basic function of locating the users. The method loadUserByUsername is the place to get the users from a database, for example, and convert the information to an implementation of the UserDetails.

This CustomUserDetailsService is, then, declared in a @Configuration class as a @Bean:

public class WebSecurityConfig {
   @Bean 
   public UserDetailsService customUserDetails() {
      return CustomUserDetailsService();
   }
   @Bean 
   public PasswordEncoder passwordEnconder() {
      return BcryptPasswordEncoder();
   }
}
Enter fullscreen mode Exit fullscreen mode

It is the same if your project need an AuthenticationManger implementation. Note that I placed a second bean with a PasswordEncoder class because we need a password encoder class to hashing them before storage.

Authentication Provider

A custom authentication can be delt with by implementing a class that extends AuthenticationProvider, which writes the authentication logic. Its interface can be seen below.

public interface AuthenticationProvider {
   Authentication authenticate (Authentication);
   boolean supports(Class<?> authentication);
}
Enter fullscreen mode Exit fullscreen mode

It is important to have in mind that the filters in the Security Filter Chain are in higher levels than the Authentication Providers. The filters analyse some characteristics of the requests, while the Authentication Provider block implements the logic.

Conclusion

In a nutshell, we discussed main building blocks to secure an application with Spring. By understanding the framework's architecture and essential components, we unlock the key to personalized security solutions.

Refferences
[1] https://livebook.manning.com/book/spring-security-in-action/welcome/v-7/1
[2] https://www.marcobehler.com/guides/spring-security
[3] https://docs.spring.io/spring-security/reference/servlet/architecture.html
[4] https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/UserDetails.html

Top comments (0)