Table of contents
- Brief Recap of Spring AOP
- Why Spring Security?
- Spring Security Architecture
- Core components of the spring security : Essentals
- Configuring Spring Security
- Securing RESTful Web Services with Spring Security
The last post [spring AOP] revolved around Spring Aspect-Oriented Programming (AOP), which plays a critical role in handling cross-cutting concerns like logging, transactions, and security, making your life a lot easier.
I have been talking about how to make your Spring-based applications work like a well-oiled machine—or, as I like to call it, a "Spring Symphony." In this post, we are going to talk about the security aspect of spring applications.
Brief Recap of Spring AOP
In our previous post, we discussed how Spring AOP can act like a conductor in an orchestra, coordinating various elements to ensure that the performance—your application—runs smoothly. We touched upon aspects, join points, advice, pointcuts, and how they all come together to address concerns that span multiple parts of an application. AOP allows you to write modular code, making it easier to manage, debug, and scale your application. And who doesn't want that, right?
But here's the kicker: even a well-conducted symphony needs a secure concert hall. That's why today we're shifting gears to talk about Spring Security.
So, are you ready to dive into the world of Spring Security? Let's get started.
Why Spring Security?
We all know security is no-more "nice-to-have"; it's a "must-have" Security can't be an afterthought; it has to be architected into the very core of your application from day one. That's where Spring Security comes into play.
If you know what's happening under the hood in the spring security, you're in a better position to customize it to fit your specific needs. And trust me, with the kinds of complex apps we're building these days, you may need that level of customization.
Spring Security Architecture
please check the diagram below and then let's try to understand the components.
The core: servlet filters
Spring Security is fundamentally built on Servlet Filters. When an HTTP request comes in, the servlet container(Tomcat, Jetty) creates a FilterChain that contains all the Filter instances and the Servlet that should process the request. /
In a Spring MVC app, this Servlet is usually an instance of DispatcherServlet.
DelegatingFilterProxy
Spring offers a DelegatingFilterProxy
that bridges the Servlet container's lifecycle and Spring’s ApplicationContext
. It allows you to register a Filter through standard Servlet container mechanisms but delegate the actual work to a Spring Bean that implements Filter
.
FilterChainProxy
The real magic happens in FilterChainProxy
, which is a special Filter provided by Spring Security. It delegates to many Filter instances through SecurityFilterChain
. This is where you'd start if you're troubleshooting Spring Security issues.
When an HTTP request arrives, FilterChainProxy decides the sequence of security filters that need to be applied. It's a crucial component you'll interact with, especially when customizing security filters or troubleshooting security issues.
Security Filter chain
These are the workhorses of Spring Security. They handle tasks like authentication, authorization, and exploit protection. The order in which they are invoked is crucial. For example, the Filter that performs authentication should be invoked before the one that handles authorization.
we can also add custom Filters to the security filter chain.
Debugging and Logging
Spring Security provides comprehensive logging at the DEBUG and TRACE levels. This is super useful when you're trying to figure out why a request was rejected.
logging.level.org.springframework.security=DEBUG
This is the property to enable the debug logs for security module .
spring security architecture flow
let's try to understand the components more by the flow, this is super intresting specially the back through flow, i recommend to go through below sequence diagram in new tab to see it better.
HTTP Request: An HTTP request comes into the application.
Servlet Container: The Servlet container (like Tomcat) intercepts the request.
DelegatingFilterProxy: The request first hits the
DelegatingFilterProxy
.FilterChainProxy:
DelegatingFilterProxy
forwards the request toFilterChainProxy
.Security Filters:
FilterChainProxy
invokes the security filters one by one. These could be for authentication, authorization, etc.DispatcherServlet: After all filters are processed,
DispatcherServlet
takes over to route the request to the appropriate controller.Controller: The controller handles the request and returns a response.
Back Through Filters: The response goes back through the security filters in reverse order.
HTTP Response: Finally, an HTTP response is returned to the client.
By looking at the above flow you may ask some important questions like,
Q. Why DelegatingFilterProxy
is forwarding request to FilterChainProxy?
FilterChainProxy
is wrapped in a DelegatingFilterProxy
to bridge the gap between the Servlet container and the Spring application context. This setup allows us to manage the FilterChainProxy as a Spring bean, enabling dependency injection and Spring's lifecycle management features. It also provides the flexibility to change security configurations within Spring without altering the Servlet container's settings.
Q. What is DispatcherServlet?DispatcherServlet
is the front controller in the Spring MVC framework, responsible for routing incoming HTTP requests to the appropriate controller methods. It acts as a gatekeeper that manages the entire request lifecycle, from pre-processing to post-processing, view resolution, and finally sending the HTTP response back to the client.
Q. Why security filters called in reverse order after controller response? (step 8)
The "back through filters" step 8 refers to the process where the response generated by your application (usually from a controller) is passed back through the same filters that processed the incoming request. However, this time, it's in the reverse order.
RequestContextFilter is one of out of the box spring security class which responsible for setting up and then cleaning up resources tied to the request.
Her is simple logging filter that logs incoming requests and outgoing responses.
@Component
public class LoggingFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Log the incoming request
logger.info("Incoming request: {} {}", request.getMethod(), request.getRequestURI());
// Continue the filter chain
filterChain.doFilter(request, response);
// Log the outgoing response
logger.info("Outgoing response: HTTP {}", response.getStatus());
}
}
Spring security also provides some handlers to handle security-related exceptions.
Spring Security leverages Spring’s event-driven model to publish various security events such as AuthenticationSuccessEvent and AuthenticationFailureEvent, which can be consumed to perform additional actions like logging or sending notifications.
Spring Security Features
Core Features
Authentication: answers "who-you-are", user identities through various mechanisms like form-based, OAuth, and LDAP.
Authorization: After authentication, this decides what you can and can't do within the app. Manages roles and permissions.
Web Security Features
Session Management
CSRF Protection: Automatically protects against Cross-Site Request Forgery attacks. CORS Configuration: Handles Cross-Origin Resource Sharing, letting your API safely interact with different origins.
Advanced Features
OAuth2 & JWT: Offers built-in but highly configurable support for OAuth2 and JWT-based authentication.
Remember Me: More than a checkbox—customize how user sessions persist between logins.
Customizable Features
Security Filter Chain: Allows you to define custom security filters and their order of execution.
Exception Handling: gives the ability to handle security-related exceptions.
Custom Authentication: Provides the flexibility to implement your own authentication strategies if the built-in ones fall short.
Core components of the spring security : Essentals
Now that we've covered the architecture of Spring Security, let's dig into its core components. Understanding these elements will equip you with the knowledge to customize and extend Spring Security to fit your application's unique requirements.
SecurityContextHolder
The SecurityContextHolder
is a storage mechanism that holds the current security context, including the user's authentication information. This context is accessible throughout your application.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Authentication and Authorization Filters
As we know now from architecture section spring Security utilizes filters to manage the security of incoming HTTP requests. These filters are crucial for performing tasks like user authentication (UsernamePasswordAuthenticationFilter
) and endpoint authorization (FilterSecurityInterceptor
).
UserDetailsService
The UserDetailsService
interface retrieves user data for authentication. When a user tries to log in, this service fetches their details to build an User
object.
PasswordEncoder
Security best practices recommend against storing passwords in plaintext. Spring Security provides the PasswordEncoder
interface to hash passwords securely.
Authentication vs. Authorization
- Authentication: This is the process of verifying the user’s identity. Spring Security supports multiple methods for this, including form-based login, OAuth2, and JWT.
Authorization: After authentication, Spring Security checks what the authenticated user is allowed to do within the application. This is usually managed through roles and permissions.
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/").permitAll()
.and().formLogin();
Configuring Spring Security
Hope you got the gist of what authentication and authorization are all about. Now, how do you set up Spring Security to work its magic? That's where configuration comes in. Here we’ll explore the two common approaches for configuring Spring Security and then dive into customizing the security filter chain.
XML Configuration vs. Java-based Configuration
In the early days of Spring, XML was the go-to for configuration. While XML configuration is still supported, Java-based configuration has become increasingly popular due to its type-safety, refactor-friendliness, and ease of use.
* XMl configurations :
For those who have legacy projects or prefer XML, you can configure Spring Security using the security namespace in an XML file.
<http>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<form-login />
</http>
***********
Java-based Configuration: If you lean toward Java, you can extend the WebSecurityConfigurerAdapter class and override its methods to set up your security configurations.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin();
}
**********
Custom Security Filter Chain
sometime we need to add your own custom logic. Spring Security allows you to add or replace filters in the chain. This is particularly useful for things like multi-tenancy or adding additional security checks.
@Bean
public SecurityFilterChain customFilterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(customFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin();
return http.build();
}
In this example, the customFilter() is inserted before UsernamePasswordAuthenticationFilter. This means that our custom filter will be invoked before the standard username and password authentication takes place.
Securing RESTful Web Services with Spring Security
When it comes to securing RESTful APIs, Spring Security offers out-of-the-box support for industry-standard methods like OAuth2 and JWT, simplifying the complexity of implementing robust security measures.
OAuth2: Spring Security's Authorization Framework
Spring Security provides first-class support for OAuth2 through its @EnableOAuth2Sso
and @EnableResourceServer
annotations. By integrating OAuth2 into its security framework, Spring Security makes it easier to specify access controls for each endpoint, perfect for applications requiring third-party integrations or complex permissioning systems.
example references: https://docs.spring.io/spring-security/reference/servlet/oauth2/login/core.html
JWT: Stateless Authentication in Spring Security
For applications that require stateless authentication, Spring Security offers built-in JWT support. This makes it straightforward to issue and validate JWT tokens without requiring any additional libraries or configurations. With a few lines in your WebSecurityConfigurerAdapter
, you can enable JWT-based authentication across your APIs.
example reference : https://www.javainuse.com/spring/boot-jwt
OAuth2 and JWT: Integrated Security with Spring
Spring Security allows for a seamless integration of OAuth2 and JWT. You can use OAuth2 for authorization—determining who can access what—while utilizing JWT for a stateless, scalable authentication mechanism. Spring Security offers the @EnableResourceServer
annotation to easily set up a resource server that can accept both OAuth2 and JWT tokens, providing a comprehensive, layered security solution.
By leveraging Spring Security's integrated features, you can effectively secure your RESTful web services, ensuring both strong authentication and precise authorization. This allows developers to focus on business logic, confident that their APIs are well-protected.
Advanced Topics in Spring Security: A Deeper Dive into Security Measures
Spring Security excels in offering solutions for advanced security topics such as Multi-Factor Authentication, Session Management, and Security Event Logging.
Multi-Factor Authentication (MFA): An Enhanced Security Posture
In the face of increasing security threats, Multi-Factor Authentication (MFA) serves as an additional layer of security. Spring Security provides a flexible foundation for implementing MFA by allowing easy integration with various multi-factor authentication mechanisms like SMS, email, and hardware tokens. This enhanced security measure ensures that users are granted access only after successfully presenting multiple pieces of valid evidence for authentication.
Session Management: Comprehensive User Interaction Control
Effective session management is crucial for maintaining the security integrity of web applications. Spring Security offers out-of-the-box features for robust session management. These include session timeout controls, concurrent session handling, and session fixation protection. By leveraging Spring Security’s session management, organizations can ensure secure and efficient user interactions with the application.
Security Event Logging: Audit-Ready Security Insights
The importance of security event logging for monitoring and auditing cannot be overstated. Spring Security offers built-in hooks for logging key security events such as authentication successes and failures, as well as access control decisions. This logged information can be seamlessly integrated with Security Information and Event Management (SIEM) systems for real-time analysis, thereby making your application not only secure but also compliant with auditing requirements.
Best Practices: The Golden Rules of Spring Security
Thanks for being with me till here so far, hope you got the gist of the awesomeness spring security has to offer, but even the most advanced tools won't save you if you're not using them wisely.
So, let's cover some best practices you should have on your radar.
Least Privilege Principle
Start by giving users and systems the least amount of access—or permissions—necessary to accomplish their tasks. Spring Security makes it easy to define roles and permissions at a granular level. It's always easier to grant additional permissions later than to plug a security hole.
Use HTTPS
This one might seem like a no-brainer, but you'd be surprised how often it's overlooked. Always use HTTPS to encrypt data in transit. Spring Security provides easy configuration options to enforce HTTPS.
Regularly Update Dependencies
Spring Security is well-maintained, and updates often contain important security patches. Make it a habit to keep your Spring Security version—and all other dependencies, for that matter—up to date.
Secure Passwords
Spring Security offers excellent support for various password-hashing algorithms. Make sure to use a strong, adaptive hashing algorithm like bcrypt. And never ever store passwords in plaintext.
Validate Inputs
Always validate inputs to protect against attacks like SQL injection and XSS. Spring Security offers built-in protections against several such vulnerabilities, but it's always good to double-check.
Examples :CsrfFilter
: Protects against CSRF attacks by validating tokens in requests.ContentSecurityPolicyHeaderWriter
: Sets headers to mitigate injection attacks like XSS.StrictTransportSecurityHeaderWriter
: Enforces HTTPS to prevent MitM attacks.
These best practices aren't just checkboxes on a security audit; they're essential habits that can make or break your application's security posture. So go ahead, make these practices second nature and let Spring Security do what it does best—keep your app secure.
Conclusion: The Final Note on Spring Security
We've journeyed through the essentials of Spring Security, from its essential role in authenticating and authorizing users to its advanced features like MFA and event logging.
Spring Security isn't just an add-on; it's a must-have that acts as the vigilant guardian of your Spring applications.
Our deep dive into its architecture revealed the importance of elements like Servlet Filters, DelegatingFilterProxy, and FilterChainProxy. These building blocks are crucial, especially when you want to get under the hood and customize security to fit your specific needs.
While we didn't delve much into code examples, the intent was to give you a comprehensive overview. It's like understanding the blueprint before constructing the building. With this guide, you're better equipped to make informed decisions, whether you're a Spring novice or a seasoned pro.
Sharing some awesome code-examples blogs below :
https://www.javainuse.com/spring/sprsec
https://spring.io/guides/gs/securing-web/
https://www.baeldung.com/security-spring
Thank you for reading.
I wish you good luck with your journey to secure your Spring Symphony.
Happy coding!
Till next time.
Love IT, Live IT, Enjoy IT !