DEV Community

Gaetano D'Orsi
Gaetano D'Orsi

Posted on

Pillars of Spring Security: A Pre-Authentication component in a complex scenario.

After a nostalgic look back at the rich history of computer science, it's time to jump into a more technical topic.

In the extensive field of application security within the Java ecosystem, Spring Security has carved out a name for itself by offering robust and adaptable solutions for protecting Spring-based applications. Despite some criticisms regarding verbosity and occasional perceptions of inadequate official support, this framework is celebrated for its customizability. It provides ready-to-use solutions for a wide range of common security concerns, along with the tools needed to handle more complex and, at times, seemingly unfeasible niche scenarios.

In the realm of system security, certain topics are more nuanced and specialized, requiring a more delicate understanding and approach. Pre-authentication is one such topic - a unique authentication scenario that, although uncommon, can prove to be critical in certain application contexts. It may seem daunting or not frequently encountered in daily scenarios, but rest assured, Spring Security has solutions in place.

In this article, our goal is to demystify this challenging topic by breaking it down to its fundamental components and demonstrating how Spring Security's components can be efficiently harnessed to handle it.

The Landscape of Pre-Authentication

In a typical application, authentication is handled internally, often involving , for example, user forms or OAuth tokens. However, in some setups and configurations, an application may rely on external systems for authentication.

These external systems verify the user's identity and then pass the authentication details, usually a user identifier, to the application. This incoming user identifier, often and support in the form of a request header or a cookie, indicates that the user has been already authenticated on an external component or system.

As uncommon as this scenario might sound, in a more fashioned it's quite prevalent in architectures where a central security component, and protected, authenticates the user and then forwards the request to the application, often in microservices-based designs or corporate environments.

Spring Security provides powerful support for these pre-authenticated scenarios, giving developers and engineers the tools to seamlessly integrate this workflow into their application's security architecture. In the next paragraph, we will deep dive into how Spring Security handles pre-authentication, underlining its versatility and its functionality in catering to both general and specific security needs.

Create your Pre-Authentication class

To manage pre-authentication, we should invole the AbstractPreAuthenticatedProcessingFilter. Despite its somewhat intimidating name, this class is designed to handle requests in which pre-authentication has been conducted by external components. The essential task here is to create a custom filter by extending the AbstractPreAuthenticatedProcessingFilter with our implementation.

This is an example:

import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

public class HeaderPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        return request.getHeader("PreAuthenticatedHeader");
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return "Not handled here";
    }
}

Enter fullscreen mode Exit fullscreen mode

In this custom filter, for a straightforward situation, we extract the pre-authenticated principal from the HTTP request header. In a more complex scenario, we may need to invoke another service for additional checks, carry out some security controls, adhere to our security protocol, and so on. The possibilities are countless.

The getPreAuthenticatedCredentials() method is not utilized because the authentication is conducted externally.

Implement your authentication's action

Next, we need to provide an authentication implementation that the filter will use to retrieve the principal's information.

After expained that, we are ready to create an implementation of AuthenticationManager for using the pre-authentication scenario created before, where we fetch principal from the request:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;

public class HeaderAuthenticator implements AuthenticationManager {

    @Override
    public Authentication authenticate(HttpServletRequest request) {
        String principal = request.getHeader("PreAuthenticatedHeader");
        if (principal != null) {
            return new UsernamePasswordAuthenticationToken(principal, null);
        }
        throw new AuthenticationServiceException("PreAuthenticatedHeader not found in the request");
    }
}
Enter fullscreen mode Exit fullscreen mode

In this implementation, the authenticate() method fetches the principal from the PreAuthenticatedHeader header of the request and returns an Authentication object using UsernamePasswordAuthenticationToken class , this class is used to hold the user's information during the authentication process.

It's important to note that the UsernamePasswordAuthenticationToken
object isn't fully authenticated yet. We only set the principal as parameter (the subject that is or has been authenticated) and leave the credentials as null because the actual authentication was done externally.

This demonstration is minimal. In a complete implementation, you would typically add additional checks, such as ensuring the header isn't empty, and perhaps other application-specific validations. If the authentication fails for any reason, you would generally throw an authentication exception or call other external handlers to perform additional computations, and so on...

Top comments (0)