Skillsbench spring-security-6
Migrate Spring Security 5 to Spring Security 6 configuration. Use when removing WebSecurityConfigurerAdapter, replacing @EnableGlobalMethodSecurity with @EnableMethodSecurity, converting antMatchers to requestMatchers, or updating to lambda DSL configuration style. Covers SecurityFilterChain beans and authentication manager changes.
git clone https://github.com/benchflow-ai/skillsbench
T=$(mktemp -d) && git clone --depth=1 https://github.com/benchflow-ai/skillsbench "$T" && mkdir -p ~/.claude/skills && cp -r "$T/tasks/spring-boot-jakarta-migration/environment/skills/spring-security-6" ~/.claude/skills/benchflow-ai-skillsbench-spring-security-6 && rm -rf "$T"
tasks/spring-boot-jakarta-migration/environment/skills/spring-security-6/SKILL.mdSpring Security 6 Migration Skill
Overview
Spring Security 6 (included in Spring Boot 3) removes the deprecated
WebSecurityConfigurerAdapter and introduces a component-based configuration approach using SecurityFilterChain beans.
Key Changes
1. Remove WebSecurityConfigurerAdapter
The biggest change is moving from class extension to bean configuration.
Before (Spring Security 5 / Spring Boot 2)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/api/public/**").permitAll() .anyRequest().authenticated(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
After (Spring Security 6 / Spring Boot 3)
@Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ); return http.build(); } @Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
2. Method Security Annotation Change (CRITICAL)
This is a required change. The
@EnableGlobalMethodSecurity annotation is removed in Spring Security 6 and must be replaced with @EnableMethodSecurity.
// BEFORE (Spring Security 5 / Spring Boot 2) - WILL NOT COMPILE in Spring Boot 3 @EnableGlobalMethodSecurity(prePostEnabled = true) // AFTER (Spring Security 6 / Spring Boot 3) - REQUIRED @EnableMethodSecurity(prePostEnabled = true)
Import Change
// BEFORE import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; // AFTER import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
Quick Migration Command
# Replace the annotation in all Java files find . -name "*.java" -type f -exec sed -i 's/@EnableGlobalMethodSecurity/@EnableMethodSecurity/g' {} + # Also update the import statement find . -name "*.java" -type f -exec sed -i 's/EnableGlobalMethodSecurity/EnableMethodSecurity/g' {} +
Verify @EnableMethodSecurity Is Present
After migration, confirm the new annotation exists:
# This should return results showing your security config class grep -r "@EnableMethodSecurity" --include="*.java" .
If this returns no results but you're using method-level security (
@PreAuthorize, @PostAuthorize, etc.), the migration is incomplete.
3. Lambda DSL Configuration
Spring Security 6 uses lambda-based configuration:
// Before (chained methods) http .csrf().disable() .cors().and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/public/**").permitAll() .anyRequest().authenticated(); // After (lambda DSL) http .csrf(csrf -> csrf.disable()) .cors(cors -> cors.configurationSource(corsConfigurationSource())) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() );
4. URL Matching Changes
antMatchers() is replaced with requestMatchers():
// Before .antMatchers("/api/**").authenticated() .antMatchers(HttpMethod.POST, "/api/users").permitAll() // After .requestMatchers("/api/**").authenticated() .requestMatchers(HttpMethod.POST, "/api/users").permitAll()
5. Exception Handling
// Before .exceptionHandling() .authenticationEntryPoint((request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED); }) .and() // After .exceptionHandling(ex -> ex .authenticationEntryPoint((request, response, authException) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); }) )
6. Headers Configuration
// Before .headers().frameOptions().disable() // After .headers(headers -> headers .frameOptions(frame -> frame.disable()) )
7. UserDetailsService Configuration
// The UserDetailsService bean is auto-detected // No need to explicitly configure in AuthenticationManagerBuilder @Service public class CustomUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) { // Implementation } }
Complete Migration Example
Before (Spring Boot 2.x)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .authenticationEntryPoint((request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage()); }) .and() .authorizeRequests() .antMatchers(HttpMethod.POST, "/api/users").permitAll() .antMatchers("/api/auth/**").permitAll() .antMatchers("/h2-console/**").permitAll() .antMatchers("/actuator/health").permitAll() .anyRequest().authenticated() .and() .headers().frameOptions().disable(); } }
After (Spring Boot 3.x)
@Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling(ex -> ex .authenticationEntryPoint((request, response, authException) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); }) ) .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.POST, "/api/users").permitAll() .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/h2-console/**").permitAll() .requestMatchers("/actuator/health").permitAll() .anyRequest().authenticated() ) .headers(headers -> headers .frameOptions(frame -> frame.disable()) ); return http.build(); } }
Servlet Namespace Change
Don't forget the servlet import change:
// Before import javax.servlet.http.HttpServletResponse; // After import jakarta.servlet.http.HttpServletResponse;
Testing Security
Update security test annotations if needed:
@SpringBootTest @AutoConfigureMockMvc class SecurityTests { @Test @WithMockUser(roles = "ADMIN") void adminEndpoint_withAdminUser_shouldSucceed() { // Test implementation } }
Migration Commands Summary
Step 1: Remove WebSecurityConfigurerAdapter
# Find classes extending WebSecurityConfigurerAdapter grep -r "extends WebSecurityConfigurerAdapter" --include="*.java" . # The class must be refactored - cannot be automated with sed
Step 2: Replace Method Security Annotation
# Replace @EnableGlobalMethodSecurity with @EnableMethodSecurity find . -name "*.java" -type f -exec sed -i 's/@EnableGlobalMethodSecurity/@EnableMethodSecurity/g' {} + # Update import find . -name "*.java" -type f -exec sed -i 's/import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity/import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity/g' {} +
Step 3: Replace antMatchers with requestMatchers
# Replace antMatchers find . -name "*.java" -type f -exec sed -i 's/\.antMatchers(/.requestMatchers(/g' {} + # Replace mvcMatchers find . -name "*.java" -type f -exec sed -i 's/\.mvcMatchers(/.requestMatchers(/g' {} + # Replace regexMatchers find . -name "*.java" -type f -exec sed -i 's/\.regexMatchers(/.requestMatchers(/g' {} +
Step 4: Replace authorizeRequests with authorizeHttpRequests
find . -name "*.java" -type f -exec sed -i 's/\.authorizeRequests(/.authorizeHttpRequests(/g' {} +
Verification Commands
Verify No Deprecated Patterns Remain
# Should return NO results grep -r "WebSecurityConfigurerAdapter" --include="*.java" . grep -r "@EnableGlobalMethodSecurity" --include="*.java" . grep -r "\.antMatchers(" --include="*.java" . grep -r "\.authorizeRequests(" --include="*.java" .
Verify New Patterns Are Present
# Should return results grep -r "@EnableMethodSecurity" --include="*.java" . grep -r "SecurityFilterChain" --include="*.java" . grep -r "\.requestMatchers(" --include="*.java" . grep -r "\.authorizeHttpRequests(" --include="*.java" .
Common Migration Pitfalls
-
@Configuration is now required separately - Before Spring Security 6,
was part of@Configuration
. Now you must add it explicitly.@EnableWebSecurity -
Lambda DSL is mandatory - The old chained method style (
) is deprecated and must be converted to lambda style.http.csrf().disable().and()... -
AuthenticationManager injection changed - Use
instead of overridingAuthenticationConfiguration.getAuthenticationManager()
.authenticationManagerBean() -
UserDetailsService auto-detection - Spring Security 6 automatically detects
beans; no need for explicit configuration.UserDetailsService -
Method security default changes -
enables@EnableMethodSecurity
and@PreAuthorize
by default (unlike the old annotation).@PostAuthorize