Spring Security
Spring Security Architecture — Filters, AuthenticationManager, SecurityContext
Understanding the delegation filter chain and security context storage.
Introduction
Spring Security is an interceptor-based security framework that protects Java applications. Rather than checking authorization checks manually inside controllers, Spring Security uses a chain of servlet filters to intercept, validate, and authorize requests before they reach business logic.
Why It Matters
Understanding the internal filter flow is critical for developers. Misconfiguring filter orders, failing to handle exceptions in filter filters, or misunderstanding how the Security Context is bound to request threads introduces severe security vulnerabilities, including authentication bypasses and context leaks.
Real-World Analogy
Think of Spring Security architecture like entering a high-security corporate headquarters:
• DelegatingFilterProxy: The outer security gate at the street entrance.
• SecurityFilterChain: A sequence of security guards standing in a hallway. One checks your luggage (CSRF filter), the next checks your ID badge (Authentication filter), and the third checks your visitor badge clearance level (Authorization filter).
• AuthenticationManager: The central database matching visitor ID records.
• SecurityContext: The visitor badge clipped to your shirt. It goes with you everywhere inside the building, showing everyone your verified roles.
Detailed Mechanics
1. The DelegatingFilterProxy
Servlets filters are initialized by the Servlet Container (like Tomcat) at startup, whereas Spring Beans are managed by the Spring ApplicationContext. DelegatingFilterProxy acts as a bridge. It is a standard servlet filter that delegates all filtering actions to a Spring Bean named FilterChainProxy, which manages the actual security filter chain.
2. The Core Filters Sequence
Spring Security executes filters in a precise order:
- CorsFilter / CsrfFilter: Checks cross-origin permissions and validates anti-forgery tokens.
- UsernamePasswordAuthenticationFilter: Extracts credentials from POST login requests and submits them for authentication.
- BasicAuthenticationFilter: Inspects standard HTTP Basic Authorization headers.
- ExceptionTranslationFilter: Catches security exceptions, redirects users to login pages, or returns HTTP 403 Access Denied.
- AuthorizationFilter: The final guard checking if the authenticated user has roles to access the requested resource path.
3. Context Storage & ThreadLocal
Once authenticated, the user details are encapsulated inside an Authentication token. This token is stored inside the SecurityContext, which in turn resides in the SecurityContextHolder. By default, Spring uses a ThreadLocal Strategy to bind this context to the active request thread. This ensures the user details are accessible anywhere in the codebase during the request processing, but are automatically cleared when the thread is returned to the pool.
Practical Example
Here is a modern Spring Boot 3 security configuration defining a custom SecurityFilterChain bean:
Quick Quiz
Q1: Which architecture component bridges the Servlet Container's lifecycle with Spring's ApplicationContext?
A) FilterChainProxy
B) DelegatingFilterProxy
C) AuthenticationManager
D) SecurityContextHolder
Answer: B — DelegatingFilterProxy is registered in web.xml/servlet context, and forwards request tasks to FilterChainProxy bean managed by Spring.
Q2: What is the default context storage mechanism used by SecurityContextHolder?
A) HttpSession Cache
B) Database Session Logging
C) ThreadLocal Storage
D) Global JVM static memory
Answer: C — Spring Security binds credentials to the current execution thread using ThreadLocal, preventing data leakages across concurrent user requests.
Scenario-Based Challenge
Production Scenario:
A backend service processes orders asynchronously. Inside a method annotated with @Async, the code attempts to retrieve the current user's profile from SecurityContextHolder.getContext().getAuthentication(). However, the returned token is null, failing order processing. Why does this happen and how do you resolve it?
This happens because @Async executes logic on a separate thread pool. Since Spring Security uses the default MODE_THREADLOCAL strategy, the security context is isolated to the primary request thread and is not copied to the asynchronous worker thread.
To resolve this:
- Configure Spring Security to inherit context to child threads by setting the system property:
spring.security.strategy=MODE_INHERITABLETHREADLOCAL. - Alternatively (safer for thread pools), wrap the thread execution task using
DelegatingSecurityContextExecutorServiceto propagate credentials during thread handoffs.
Interview Questions
1. Conceptual: What is the difference between AuthenticationManager and AuthenticationProvider?
AuthenticationManager is the main entry point interface for authentication requests. It delegates actual credential checks to a list of configured AuthenticationProvider instances. Each provider is specialized in a specific verification method (e.g. DaoAuthenticationProvider for database queries, LdapAuthenticationProvider for directory queries).
2. Concept: How can you write custom filters and insert them at specific positions in Spring Security?
Define a class extending OncePerRequestFilter. In your security configuration chain, insert it using position modifier methods:
http.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class) or http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class).
Production Considerations
Avoid writing custom filter exception throw paths blindly. Servlets filters run before controller contexts; standard controller advice classes annotated with @ControllerAdvice cannot catch exceptions thrown in filters. Implement a dedicated filter error handler bean or delegate failures to the standard HandlerExceptionResolver to render standardized RFC 7807 error responses.