17 Security Architecture How to Understand the Overall Structure of the Spring Security Framework

17 Security Architecture - How to Understand the Overall Structure of the Spring Security Framework #

When designing web applications, on the one hand, system security is an important but easily overlooked topic because developers lack an understanding of web security mechanisms. On the other hand, system security is a very comprehensive topic because the technology involved in the system is complex. Therefore, in this lecture, we will discuss a new topic: the requirements and implementation solutions related to security in Spring.

Within the Spring family, Spring Security provides developers with a security development framework. Let’s take a look at the overall architecture of security in Spring.

Security Requirements for Web Applications #

In a software system, the content that needs to be accessed is defined as a resource, and the core goal of security design is to protect these resources to ensure controlled and secure access by external requests.

In a web application, we understand the exposed RESTful endpoints as resources, and there are several common technology systems in the industry for securing access to these HTTP endpoints.

Before explaining these technology systems, let’s first look at two commonly confused concepts in the security field: authentication and authorization.

Authentication refers to the need to first determine “who you are,” that is, the system must be able to determine the legitimate identity of the visitor for each access request.

Once we have determined “who you are,” we can determine “what you can do.” This step is called authorization. Generally, a commonly used authorization model is based on a permission management system, which is a solution that combines resources, permissions, roles, and users.

When we combine authentication and authorization, we first determine the valid identity of the resource requester and then determine their legitimate permission to access the resource. This whole process forms a common solution for managing the security of the system, as shown in the following diagram:

Drawing 1.png

Security access diagram based on authentication and authorization mechanisms

The above diagram represents a common solution, and in different application scenarios and technology systems, specific implementation strategies can be derived. For example, although the authentication and authorization models for web application systems are similar to the diagram above, they have their own particularities in their specific design and implementation processes.

In the web application ecosystem, because the requirements for authentication are relatively clear, we need to build a complete storage system to store and maintain user information, and ensure that this user information can be used reasonably in the process of handling requests.

The situation is relatively more complex for authorization. For a specific web application, the first problem we face is how to determine if an HTTP request has the permission to access it. Even if this request has the permission to access the application, it does not mean that it can access all the HTTP endpoints it has. For example, certain core functionalities may require higher permissions to access. This involves the second problem we need to solve: how to finely manage the permissions for access? As shown in the following diagram:

Drawing 3.png

Illustration of access authorization for a web application

In the diagram above, assuming that this request has the permission to access the web application but does not have the permission to access endpoint 1, if we want to achieve this effect, our general approach is to introduce a role system. First, different users are assigned different levels of roles (different levels of roles correspond to different access permissions), and then each request is bound to a role (meaning that the request has the permission to access).

Next, let’s integrate authentication and authorization and outline the implementation solution for security in web application access, as shown in the following diagram:

Drawing 5.png

Integration of authentication and authorization diagram

From the above diagram, we can see that the user first completes user authentication by passing user credentials in the request, and then access permissions are obtained based on the role information contained in the user’s data. Finally, access authorization for HTTP endpoints is completed.

When designing the security of a web application, we need to consider authentication and authorization because they are the core focus. In technical implementation scenarios, whenever user authentication is involved, encryption of sensitive information such as user passwords is necessary. For scenarios involving user passwords, we mainly use one-way hash encryption algorithms to encrypt sensitive information. About one-way hash encryption algorithm, it is commonly used to generate message digests, characterized by one-way irreversible and fixed length of the ciphertext, and also has the advantage of “collision” less, that is, a slight difference in plaintext will result in completely different ciphertext. Among them, the common implementation algorithms of one-way hash encryption are MD5 (Message Digest 5) and SHA (Secure Hash Algorithm). In the JDK-embedded MessageDigest class, because it already contains the default implementations of these algorithms, we can directly call the methods.

In everyday development, the typical operation sequence diagram for encrypting passwords is as follows:

Drawing 3.png

One-way hash encryption with salting mechanism

In the above figure, we introduce the salting mechanism to further enhance the security of encrypted data. The so-called salting means that when initializing plaintext data, the system automatically adds some additional data to the plaintext and then performs the hashing.

Currently, the concepts of one-way hash encryption and salting have been widely used in the password generation and verification processes in the system login process, such as the Spring Security framework we are about to introduce.

Spring Security Architecture #

Spring Security is one of the long-standing frameworks in the Spring family. Before the advent of Spring Boot, Spring Security had been developed for many years. Although Spring Security has rich functionality, compared with lightweight security frameworks like Apache Shiro, its advantages are not so obvious. In addition, the process of integrating and configuring the Spring Security framework in the application is relatively complex, so its development process is not so smooth.

However, with the rise of Spring Boot, the development of Spring Security has been promoted. It provides a complete set of automatic configuration solutions specifically for Spring Security, enabling developers to use Spring Security with zero configuration.

In this session, we will not explain how to use the Spring Security framework, but first outline the architectural design provided by the framework for the security requirements mentioned earlier.

Filter Chain in Spring Security #

Compared with most frameworks that handle web requests in business logic, we find that Spring Security adopts the pipe-filter architecture pattern, as shown in the following diagram:

Drawing 8.png

Diagram of the pipe-filter architecture pattern

In the above diagram, we can see that the component that handles business logic is called a filter, and the connection between adjacent filters that handle results is called a pipe. They form a filter chain, which is the core of Spring Security.

Once the project is started, the filter chain will be automatically configured, as shown in the following diagram:

Drawing 10.png

Filter chain in Spring Security

In the above diagram, we can see several common filters such as BasicAuthenticationFilter and UsernamePasswordAuthenticationFilter. These classes directly or indirectly implement the Filter interface in the Servlet class, and complete a specific authentication mechanism. For example, the BasicAuthenticationFilter in the above diagram is used to authenticate the user’s identity, and the UsernamePasswordAuthenticationFilter is used to check the entered username and password, and determine whether to pass the result to the next filter based on the authentication result.

Please note that the end of the entire Spring Security filter chain is a FilterSecurityInterceptor, which is also fundamentally a Filter, but it is different from other filters used to complete authentication operations. Because its core function is to implement permission control, that is, to determine whether the request can access the target HTTP endpoint. Because we can divide the granularity of authorization control of the FilterSecurityInterceptor to the method level, it can meet the requirement for fine-grained access control mentioned earlier.

Through the above analysis, we know that in Spring Security, the authentication and authorization security requirements are mainly implemented through a series of filters.

Based on the filter chain, let’s take a closer look at the core class structure in Spring Security.

Core Classes in Spring Security #

Let’s take the most basic UsernamePasswordAuthenticationFilter as an example. The definition and the core method, attemptAuthentication, of this class are shown in the following code:

public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);

        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    ...
}

Based on the above method and by referring to the Spring Security source code, we introduce a series of core classes in the framework and clarify the interaction structure among them, as shown in the following diagram:

Lark20210112-182830.png

Spring Security Core Class Diagram

Many classes in the above diagram can be understood by their names.

Taking SecurityContextHolder located in the bottom left corner as an example, it is a typical Holder class that stores the security context object SecurityContext of the application, which contains the most recently used authentication information in the system’s requests. We boldly guess that it must use ThreadLocal internally to ensure thread-safe access.

As shown in the code of UsernamePasswordAuthenticationFilter, after an HTTP request reaches the system, user authentication will be completed through a series of filters, and then the specific work will be handed over to the AuthenticationManager. Once the AuthenticationManager successfully verifies the authentication, it will return a filled Authentication instance.

AuthenticationManager is an interface, which relies on the AuthenticationProvider interface to complete specific authentication work when implemented by the ProviderManager class.

In Spring Security, there are a large number of implementations of the AuthenticationProvider interface, each of which completes various authentication operations. When performing specific authentication work, Spring Security will definitely use user details, and the UserDetailsService service on the right side of the above diagram is used for managing user details.

Regarding many other core classes in the above diagram, we will continue to delve into them in the upcoming Lecture 18 “User Authentication: How to Build a User Authentication System Based on Spring Security?”.

Summary and Preview #

In this lecture, we began to explore the security of web applications. In this field, because authentication and authorization are still the most basic security controls, we systematically analyzed the solutions for authentication and authorization and introduced the Spring Security framework in the Spring family to implement these solutions. At the same time, we analyzed the basic architecture of Spring Security.

After introducing the basic concepts of authentication and authorization, in Lecture 18, we will provide a detailed introduction to the implementation process based on the SpringCSS case system. First, we need to focus on how to use the Spring Security framework to manage the user authentication process.