Spring Security – Deprecated WebSecurityConfigurerAdapter

After the WebSecurityConfigurerAdapter class was deprecated and then removed in Spring 6, this Spring Security tutorial aims to help in migrating to the latest Spring Security 6. It covers the major changes and new features introduced in the latest version, along with the challenges that may arise during the Spring security version upgrade.

1. Major Changes to API

1.1. Java 17 and Jakarta Namespace

Java 17 is the baseline Java version for Spring Boot 3 and Spring 6, so make sure you have upgraded the JDK version before upgrading the Spring framework version. This will make sure that when you version upgrade the Spring framework, the new errors are due to Spring and not because of other causes.

Also, Spring 6 replaced Java EE with Jakarta EE; the minimum supported version is Jakarta EE9. This breaks backward compatibility and is the source of most issues in the migration process. It will use the jakarta packages namespace instead of javax namespace.

1.2. WebSecurityConfigurerAdapter had been Deprecated, now Removed

Traditionally, WebSecurityConfigurerAdapter was used to customize the HTTP security features, such as endpoints authorization or the authentication manager configuration etc.

In Spring Security version 5.7.0-M2, WebSecurityConfigurerAdapter class had been deprecated to encourage the component-based security approach to configure HttpSecurity by creating a SecurityFilterChain bean. This approach was introduced in version Spring Security 5.4.

In the following example, we use the WebSecurityConfigurerAdapter to configure Spring Security to allow access to endpoints that match “/public/**”, while requiring authentication for everything else.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
    protected void configure(HttpSecurity http) throws Exception {
       http.authorizeRequests()
               .antMatchers("/public/**")
                    .permitAll()
               .anyRequest()
                    .authenticated()
               .and()
                .formLogin();
    }
}

In Spring Security 6, the same configuration has to be written as follows. Note that the HttpSecurity object is used to configure how HTTP requests are secured.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        
        httpSecurity.authorizeHttpRequests()
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();
        
        return  httpSecurity.build();
    }
}

1.3. Replace antMatchers, mvcMatchers, regexMatchers & authorizeRequests with requestMatchers and authorizeHttpRequests

Spring Security team also removed the deprecated methods such as antMatchers, mvcMatchers, and regexMatchers. Instead, we should use the requestMatchers or securityMatchers methods.

Furthermore, the authorizeRequests method has been deprecated and we should use the authorizeHttpRequests method instead.

For example, the following configuration is written with WebSecurityConfigurerAdapter:

http.authorizeRequests()
  .antMatchers("/h2-console/**").permitAll()
  .anyRequest().authenticated();

With Spring Boot 3 Security, we need to write as follows;

http.authorizeHttpRequests()
  .requestMatchers("/h2-console/**").permitAll()
  .anyRequest().authenticated();

1.4. @EnableGlobalMethodSecurity is Deprecated

The @EnableGlobalMethodSecurity was used to enable method-level security across the entire application using the annotations such as @Secured, @PreAuthorize, @PostAuthorize etc.

In Spring Security 6, @EnableGlobalMethodSecurity has been deprecated in favor of @EnableMethodSecurity. There are several reasons for this change, but most importantly it enables the pre and post annotations, by default. This means that we no longer need to set ‘prePostEnabled = true‘ explicitly.

Now we can replace the following declaration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
  //...
}

with the new declaration as follows:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
  //...
}

1.5. Default Authorities foroauth2Login()

In earlier versions of Spring Security, the default authority given to a user who authenticates via oauth2Login() for both OAuth2 and OIDC providers was ROLE_USER.

However, in Spring Security 6, the default authority given to a user who authenticates with an OAuth2 provider is OAUTH2_USER, while the default authority given to a user who authenticates with an OpenID Connect 1.0 provider is OIDC_USER.

2. Changes to Common Configurations

2.1. inMemoryAuthentication() to InMemoryUserDetailsManager

UserDetailsManager is a sub-interface of UserDetailsService that extends it with additional methods for managing user accounts. InMemoryUserDetailsManager is an implementation of the UserDetailsManager interface that is used to store user details in memory, typically used for unit testing and POC purposes.

In the following example, we use WebSecurityConfigurerAdapter to configure the AuthenticationManager to use in-memory authentication.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {

		UserDetails admin = User.withDefaultPasswordEncoder()
			.username("admin")
			.password("1234")
			.roles("ADMIN")
			.build();

		auth.inMemoryAuthentication().withUser(admin);
	}
}

In Spring Security 6, we can define a bean of type InMemoryUserDetailsManager and provide the user details.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public InMemoryUserDetailsManager inMemoryUserDetailsManager(){

		UserDetails admin = User.withDefaultPasswordEncoder()
			.username("admin")
			.password("1234")
			.roles("ADMIN")
			.build();
			
		return new InMemoryUserDetailsManager(admin);
	}
}

2.2. jdbcAuthentication() to JdbcUserDetailsManager

Another implementation of the UserDetailsManager interface is JdbcUserDetailsManager. It stores user information in a relational database using JDBC. It can be used with any JDBC-compliant database and supports password encoding, account locking, and other user management features.

In the following example, we configure JDBC authentication using WebSecurityConfigurerAdapter by overriding the configure() method. Note that Spring uses the DataSource bean for connecting to the database.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	private DataSource dataSource;

	@Override
	public void configure(AuthenticationManagerBuilder auth) throws Exception {

		auth.jdbcAuthentication()
		.dataSource(dataSource)
		.withDefaultSchema()
		.withUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER"));
	}
}

When we run the application, the withDefaultSchema() method is used to create two tables in our embedded database: users and authorities. We also add our own user using the withUser() method.

Here’s an example of how to achieve the same thing by registering a JdbcUserDetailsManager bean:

@Configuration
@EnableWebSecurity
public class SecurityConfig  {

	@Autowired
	private DataSource dataSource;

	@Bean
	JdbcUserDetailsManager jdbcUserDetailsManager(){

		UserDetails user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER").build();

		JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource);
		jdbcUserDetailsManager.createUser(user);
		return jdbcUserDetailsManager;
	}
}

3. Conclusion

This tutorial discussed major changes to Spring Security 6 and how to adapt to those changes using easy-to-follow code examples. As mentioned earlier, it is advised to upgrade the application to Java 17 before upgrading security to isolate the defects that are caused by the Spring 6 migration.

Happy Learning !!

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.