From 60e573de26f44d050deed055123a6810f5cf65ce Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Mon, 14 Nov 2022 10:53:13 -0700 Subject: [PATCH] Add WebSecurityConfigurerAdapter Preparation Steps Issue gh-10902 --- docs/modules/ROOT/pages/migration.adoc | 456 +++++++++++++++++++++++++ 1 file changed, 456 insertions(+) diff --git a/docs/modules/ROOT/pages/migration.adoc b/docs/modules/ROOT/pages/migration.adoc index b66102141c..ede5b426af 100644 --- a/docs/modules/ROOT/pages/migration.adoc +++ b/docs/modules/ROOT/pages/migration.adoc @@ -3064,6 +3064,462 @@ private fun grantedAuthoritiesMapper(): GrantedAuthoritiesMapper { ---- ==== +=== Stop Using `WebSecurityConfigurerAdapter` + +==== Publish a `SecurityFilterChain` Bean + +Spring Security 5.4 introduced the capability to publish a `SecurityFilterChain` bean instead of extending `WebSecurityConfigurerAdapter`. +In 6.0, `WebSecurityConfigurerAdapter` is removed. +To prepare for this change, you can replace constructs like: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((authorize) -> authorize + .anyRequest().authenticated() + ) + .httpBasic(withDefaults()); + } + +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration: WebSecurityConfigurerAdapter() { + + @Override + override fun configure(val http: HttpSecurity) { + http { + authorizeHttpRequests { + authorize(anyRequest, authenticated) + } + + httpBasic {} + } + } + +} +---- +==== + +with: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((authorize) -> authorize + .anyRequest().authenticated() + ) + .httpBasic(withDefaults()); + return http.build(); + } + +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration { + + @Bean + fun filterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + authorize(anyRequest, authenticated) + } + httpBasic {} + } + return http.build() + } + +} +---- +==== + +==== Publish an `AuthenticationManager` Bean + +As part of `WebSecurityConfigurerAdapeter` removal, `configure(AuthenticationManagerBuilder)` is also removed. +Preparing for its removal will differ based on your reason for using it. + +===== LDAP Authentication + +If you are using `auth.ldapAuthentication()` for xref:servlet/authentication/passwords/ldap.adoc[LDAP authentication support], you can replace: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .ldapAuthentication() + .userDetailsContextMapper(new PersonContextMapper()) + .userDnPatterns("uid={0},ou=people") + .contextSource() + .port(0); + } + +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration: WebSecurityConfigurerAdapter() { + + override fun configure(auth: AuthenticationManagerBuilder) { + auth + .ldapAuthentication() + .userDetailsContextMapper(PersonContextMapper()) + .userDnPatterns("uid={0},ou=people") + .contextSource() + .port(0) + } + +} +---- +==== + +with: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration { + @Bean + public EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() { + EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean = + EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer(); + contextSourceFactoryBean.setPort(0); + return contextSourceFactoryBean; + } + + @Bean + AuthenticationManager ldapAuthenticationManager(BaseLdapPathContextSource contextSource) { + LdapBindAuthenticationManagerFactory factory = + new LdapBindAuthenticationManagerFactory(contextSource); + factory.setUserDnPatterns("uid={0},ou=people"); + factory.setUserDetailsContextMapper(new PersonContextMapper()); + return factory.createAuthenticationManager(); + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration { + @Bean + fun contextSourceFactoryBean(): EmbeddedLdapServerContextSourceFactoryBean { + val contextSourceFactoryBean: EmbeddedLdapServerContextSourceFactoryBean = + EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer() + contextSourceFactoryBean.setPort(0) + return contextSourceFactoryBean + } + + @Bean + fun ldapAuthenticationManager(val contextSource: BaseLdapPathContextSource): AuthenticationManager { + val factory = LdapBindAuthenticationManagerFactory(contextSource) + factory.setUserDnPatterns("uid={0},ou=people") + factory.setUserDetailsContextMapper(PersonContextMapper()) + return factory.createAuthenticationManager() + } +} +---- +==== + +===== JDBC Authentication + +If you are using `auth.jdbcAuthentication()` for xref:servlet/authentication/passwords/jdbc.adoc[JDBC Authentication support], you can replace: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + @Bean + public DataSource dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .build(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + auth.jdbcAuthentication() + .withDefaultSchema() + .dataSource(this.dataSource) + .withUser(user); + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration: WebSecurityConfigurerAdapter() { + @Bean + fun dataSource(): DataSource { + return EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .build() + } + + override fun configure(val auth: AuthenticationManagerBuilder) { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + auth.jdbcAuthentication() + .withDefaultSchema() + .dataSource(this.dataSource) + .withUser(user) + } +} +---- +==== + +with: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration { + @Bean + public DataSource dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION) + .build(); + } + + @Bean + public UserDetailsManager users(DataSource dataSource) { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); + users.createUser(user); + return users; + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration { + @Bean + fun dataSource(): DataSource { + return EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION) + .build() + } + + @Bean + fun users(val dataSource: DataSource): UserDetailsManager { + val user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + val users = JdbcUserDetailsManager(dataSource) + users.createUser(user) + return users + } +} +---- +==== + +===== In-Memory Authentication + +If you are using `auth.inMemoryAuthentication()` for xref:servlet/authentication/passwords/in-memory.adoc[In-Memory Authentication support], you can replace: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + auth.inMemoryAuthentication() + .withUser(user); + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration: WebSecurityConfigurerAdapter() { + override fun configure(val auth: AuthenticationManagerBuilder) { + val user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + auth.inMemoryAuthentication() + .withUser(user) + } +} +---- +==== + +with: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration { + @Bean + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build(); + return new InMemoryUserDetailsManager(user); + } +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration { + @Bean + fun userDetailsService(): InMemoryUserDetailsManager { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("password") + .roles("USER") + .build() + return InMemoryUserDetailsManager(user) + } +} +---- +==== + +===== Other Scenarios + +If you are using `AuthenticationManagerBuilder` for something more sophisticated, you can xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationmanager[publish your own `AuthenticationManager` `@Bean`] or wire an `AuthenticationManager` instance into the `HttpSecurity` DSL with {security-api-url}org/springframework/security/config/annotation/web/builders/HttpSecurity.html#authenticationManager(org.springframework.security.authentication.AuthenticationManager)[`HttpSecurity#authenticationManager`]. + +==== Publish a `WebSecurityCustomizer` Bean + +Spring Security 5.4 https://github.com/spring-projects/spring-security/issues/8978[introduced `WebSecurityCustomizer`] to replace `configure(WebSecurity web)` in `WebSecurityConfigurerAdapter`. +To prepare for its removal, you can replace code like the following: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + public void configure(WebSecurity web) { + web.ignoring().antMatchers("/ignore1", "/ignore2"); + } + +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration: WebSecurityConfigurerAdapter() { + + override fun configure(val web: WebSecurity) { + web.ignoring().antMatchers("/ignore1", "/ignore2") + } + +} +---- +==== + +with: + +==== +.Java +[source,java,role="primary"] +---- +@Configuration +public class SecurityConfiguration { + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2"); + } + +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Configuration +open class SecurityConfiguration { + + @Bean + fun webSecurityCustomizer(): WebSecurityCustomizer { + return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2") + } + +} +---- +==== + == Reactive === Use `AuthorizationManager` for Method Security