Securing the Path: A Comprehensive Guide to Spring Security Migration

Marcelo Domingues
6 min readSep 9, 2023

--

Reference Image

Introduction:

Security is paramount in today’s digital landscape, and Spring Security has long been the go-to choice for securing Java applications. With the release of Spring Security 6.1, a significant enhancement called Lambda DSL has been introduced, allowing HTTP security to be configured using lambdas. In this comprehensive guide, we’ll explore the motivations behind upgrading to Spring Security 6.1, the use of Lambda DSL, and provide hands-on examples for a successful migration.

1. Understanding the Need for Migration:

  • Security Enhancements: Spring Security 6.1 brings critical security updates and features.
  • Compliance: Ensure your application aligns with the latest security standards and regulations.
  • Performance: Benefit from optimizations for improved security performance.
  • Feature Enrichment: Access advanced authentication and authorization features.

2. Preparing for Migration:

  • Dependency Analysis: Examine your project’s dependencies, including Spring Security and related libraries, to ensure compatibility with version 6.1.
  • Documentation: Create or update detailed documentation about your current security setup, including authentication mechanisms, authorization rules, and custom filters.
  • Testing Strategy: Develop a comprehensive testing strategy that includes unit tests, integration tests, and security testing tools.

3. Choosing the Target Version:

  • Version Selection: Select Spring Security 6.1 as your target version based on long-term support and feature compatibility.
  • Dependency Updates: Ensure that other dependencies, such as Spring Framework and Java, are compatible with Spring Security 6.1.

4. Dependency Management:

  • Maven or Gradle Updates: Modify your project’s build file (pom.xml or build.gradle) to include Spring Security >6.1.
  • Update Related Dependencies: Check for any other dependencies that need updating due to compatibility with the new Spring Security version.

5. Configuration and Codebase Updates:

  • Lambda DSL Configuration: Take advantage of Lambda DSL to configure HTTP security using expressive lambdas for improved readability and flexibility.
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/blog/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin ->
formLogin
.loginPage("/login")
.permitAll()
)
.rememberMe(withDefaults());
}
}

6. Lambda DSL Configuration Tips:

  • In the Lambda DSL, there’s no need to chain configuration options using the .and() method. The HttpSecurity instance is automatically returned for further configuration after the call to the lambda method.
  • Use withDefaults() to enable security features using the defaults provided by Spring Security, which is a convenient shortcut for the lambda expression it -> {}.

7. WebFlux Security with Lambda DSL:

  • You can also configure WebFlux security using lambdas in a similar manner to HTTP security. Below is an example configuration:
@EnableWebFluxSecurity
public class SecurityConfig {

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges ->
exchanges
.pathMatchers("/blog/**").permitAll()
.anyExchange().authenticated()
)
.httpBasic(withDefaults())
.formLogin(formLogin ->
formLogin
.loginPage("/login")
);
return http.build();
}
}

8. Goals of the Lambda DSL:

  • Automatic Indentation: Lambda DSL provides automatic indentation, enhancing the readability of your security configuration.
  • No Need for .and(): Eliminate the need to chain configuration options using .and(), simplifying your security code.
  • Consistent Style: Lambda DSL aligns Spring Security’s configuration style with other Spring DSLs like Spring Integration and Spring Cloud Gateway.

Understanding HeadersConfigurer:

HeadersConfigurer is a part of Spring Security's configuration that allows you to configure various HTTP response headers, such as those related to security and content delivery policies. As of the information you provided, it appears that certain methods and configurations within HeadersConfigurer are deprecated and subject to removal in future versions, particularly in Spring Security 7.0.

Here’s an explanation of the deprecated methods and configurations and how you can adapt your code to the changes:

Deprecated cacheControl, contentSecurityPolicy, and Other Configurations

Several configurations related to headers like cacheControl, contentSecurityPolicy, contentTypeOptions, crossOriginEmbedderPolicy, crossOriginOpenerPolicy, crossOriginResourcePolicy, frameOptions, httpPublicKeyPinning, httpStrictTransportSecurity, permissionsPolicy, referrerPolicy, and xssProtection have been marked as deprecated.

These deprecations indicate that the way these headers are configured will change in Spring Security 7.0.

Suggested Changes

To adapt your code to these changes, you can use the Customizer interface to provide custom configurations for these headers. Instead of directly calling methods like cacheControl(), contentSecurityPolicy(), etc., you'll use the corresponding Customizer methods.

Here’s an example of how you can configure CacheControl and Content-Security-Policy headers using the new Customizer approach:

Old Way (Deprecated):

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.cacheControl().disable()
.contentSecurityPolicy("default-src 'self'");
}
}

New Way (Using Customizers):

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.Customizer;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
.cacheControl(Customizer.disable())
.contentSecurityPolicy(Customizer.withDefaults());
}

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
}

In the new approach, Customizer.disable() is used to disable the cache control headers, and Customizer.withDefaults() is used to apply default content security policy headers.

The exact configuration you need may vary based on your application’s requirements, but this should give you an idea of how to adapt to the changes in HeadersConfigurer for Spring Security 7.0 and beyond.

Additional Information:

Why Upgrade to Spring Security 6.1?

Spring Security 6.1 introduces the Lambda DSL, which is a game-changer for configuring security in Java applications. The Lambda DSL allows you to define security rules using expressive lambda expressions, making your security configuration more concise and readable. Here are some key reasons to consider upgrading:

  • Improved Readability: Lambda DSL eliminates the need for chaining configuration options with .and(). This results in cleaner and more readable security code.
  • Automatic Indentation: Lambda DSL automatically indents your security configuration, enhancing code formatting and maintainability.
  • Consistent Style: The Lambda DSL aligns Spring Security’s configuration style with other Spring DSLs, providing a consistent experience for Spring developers.

HeadersConfigurer and Spring Security 7.0:

The HeadersConfigurer in Spring Security allows you to configure various HTTP response headers, including security-related headers. However, it’s essential to be aware of changes coming in Spring Security 7.0. Several header-related configurations are marked as deprecated, and the recommended approach is to use Customizers for these headers.

Real-World Example:

Here’s a real-world example of configuring Spring Security 6.1 with Lambda DSL and Customizers:

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable())
.headers(headers -> {
headers
.httpStrictTransportSecurity(Customizer.withDefaults())
.xssProtection(Customizer.withDefaults())
.contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"));
});
return http.build();
}

@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}

In this example:

  • We configure security rules with Lambda DSL using authorizeHttpRequests. Requests to "/public/**" are allowed without authentication, while any other request requires authentication.
  • httpBasic(Customizer.withDefaults()) configures HTTP Basic authentication with default settings.
  • We disable CSRF protection with .csrf(csrf -> csrf.disable()).
  • The headers section configures security-related HTTP response headers. We use Customizers like httpStrictTransportSecurity, xssProtection, and contentSecurityPolicy with default settings to secure the application's headers.
  • We also define a simple userDetailsService to provide user authentication details for testing purposes.

This example demonstrates how to secure a web application using Spring Security 6.1’s Lambda DSL and Customizers to configure security headers. It ensures that public routes are accessible without authentication while protecting other routes with HTTP Basic authentication and securing response headers.

Conclusion:

Migrating to Spring Security 6.1 with Lambda DSL is a significant step towards enhancing the security of your Java applications. By understanding the motivations behind migration, meticulous preparation, and embracing the Lambda DSL for configuration, you can confidently secure your applications for the future. Security is an ongoing journey, and staying up-to-date with the latest security practices is crucial in today’s ever-evolving threat landscape. Secure the path ahead with Spring Security 6.1 and Lambda DSL!

Special Note:

Special Thanks to ChatGPT for giving/generating this excellent image and title, since I was out of ideas and my creative level isn’t great. 🙂

Explore More on Spring and Java Development:

Enhance your skills with our selection of articles:

  • Spring Beans Mastery (Dec 17, 2023): Unlock advanced application development techniques. Read More
  • JSON to Java Mapping (Dec 17, 2023): Streamline your data processing. Read More
  • Spring Rest Tools Deep Dive (Nov 15, 2023): Master client-side RESTful integration. Read More
  • Dependency Injection Insights (Nov 14, 2023): Forge better, maintainable code. Read More
  • Spring Security Migration (Sep 9, 2023): Secure your upgrade smoothly. Read More
  • Lambda DSL in Spring Security (Sep 9, 2023): Tighten security with elegance. Read More
  • Spring Framework Upgrade Guide (Sep 6, 2023): Navigate to cutting-edge performance. Read More

--

--

Marcelo Domingues

🚀 Senior Software Engineer | Crafting Code & Words | Empowering Tech Enthusiasts ✨ 📲 LinkedIn: https://www.linkedin.com/in/marcelogdomingues/