springspring-securityspring-kotlin

Spring in Kotlin: from 5.3 to 6.0 security Configuration


I'm facing lots of issues in doing Spring security configurations that I used to have in v5.3 applied in v6.

This is the file I had

@Configuration
@EnableWebSecurity
class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {

    @Autowired
    lateinit var service: UserService

    /**
     * Will be resolved into: WebSecurityEntryPoint injected instance.
     */
    @Autowired
    lateinit var unauthorizedHandler: AuthenticationEntryPoint

    @Autowired
    lateinit var successHandler: WebSecurityAuthSuccessHandler

    @Autowired
    override fun configure(auth: AuthenticationManagerBuilder) {
        auth.authenticationProvider(authenticationProvider())
    }

    override fun configure(http: HttpSecurity?) {
        http
                ?.csrf()?.disable()
                ?.exceptionHandling()
                ?.authenticationEntryPoint(unauthorizedHandler)
                ?.and()
                ?.authorizeRequests()
                /**
                 * Access to Notes and Todos API calls is given to any authenticated system user.
                 */
                ?.antMatchers("/notes")?.authenticated()
                ?.antMatchers("/notes/**")?.authenticated()
                ?.antMatchers("/todos")?.authenticated()
                ?.antMatchers("/todos/**")?.authenticated()
                /**
                 * Access to User API calls is given only to Admin user.
                 */
                ?.antMatchers("/users")?.hasAnyAuthority("ADMIN")
                ?.antMatchers("/users/**")?.hasAnyAuthority("ADMIN")
                ?.and()
                ?.formLogin()
                ?.successHandler(successHandler)
                ?.failureHandler(SimpleUrlAuthenticationFailureHandler())
                ?.and()
                ?.logout()
    }

    @Bean
    fun authenticationProvider(): DaoAuthenticationProvider {
        val authProvider = DaoAuthenticationProvider()
        authProvider.setUserDetailsService(service)
        authProvider.setPasswordEncoder(encoder())
        return authProvider
    }

    @Bean
    fun encoder(): PasswordEncoder = BCryptPasswordEncoder(11)

    @Bean
    fun accessDecisionManager(): AccessDecisionManager {
        val decisionVoters = Arrays.asList(
                WebExpressionVoter(),
                RoleVoter(),
                AuthenticatedVoter()
        )
        return UnanimousBased(decisionVoters)
    }

}

I used the documentation in Spring.io

https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

and I'm just hitting the wall since then. their documentation is not helpful and the new dependencies aren't working the same. how can this be done now?

P.S: I often keep getting this error:

Caused by: java.lang.ClassNotFoundException: org.springframework.security.core.context.DeferredSecurityContext

which i couldn't find anywhere


Solution

  • Okey... I managed to solve it this way first I had to add the security dependency for v6 implementation("org.springframework.security:spring-security-core:6.0.1")

    and I made the Security Configuration this way

    @Configuration
    @EnableWebSecurity
    class SecurityConfiguration(
        private val userService: UserService,
        private val unauthorizedHandler: AuthenticationEntryPoint,
        private val successHandler: WebSecurityAuthSuccessHandler
    ) {
    
        /**
         * Will be resolved into: WebSecurityEntryPoint injected instance.
         */
        @Bean
        fun myPasswordEncoder(): PasswordEncoder {
            return BCryptPasswordEncoder(11)
        }
    
        @Primary
        fun configureAuthentication(auth: AuthenticationManagerBuilder): AuthenticationManagerBuilder {
            return auth.authenticationProvider(authenticationProvider())
        }
    
    
        @Bean
        fun authenticationProvider(): DaoAuthenticationProvider {
            val authProvider = DaoAuthenticationProvider()
            authProvider.setUserDetailsService(userService)
            authProvider.setPasswordEncoder(myPasswordEncoder())
            return authProvider
        }
    
        @Bean
        fun accessDecisionManager(): AccessDecisionManager {
            val decisionVoter = listOf(
                WebExpressionVoter(),
                RoleVoter(),
                AuthenticatedVoter()
            )
            return UnanimousBased(decisionVoter)
        }
    
        @Bean
        fun configureHttpSecurity(httpSecurity: HttpSecurity): SecurityFilterChain {
             httpSecurity
                 .csrf().disable()
                 .exceptionHandling()
                 .authenticationEntryPoint(unauthorizedHandler)
                 .and()
                 .authorizeHttpRequests()
                 /**
                  * Access to Notes and Todos API calls is given to any authenticated system user.
                  */
                 .requestMatchers("/notes").authenticated()
                 .requestMatchers("/notes/**").authenticated()
                 .requestMatchers("/todos").authenticated()
                 .requestMatchers("/todos/**").authenticated()
                 /**
                  * Access to User API calls is given only to Admin user.
                  */
                 .requestMatchers("/users").hasAnyAuthority("ADMIN")
                 .requestMatchers("/users/**").hasAnyAuthority("ADMIN")
                 .and()
                 .formLogin()
                 .successHandler(successHandler)
                 .failureHandler(SimpleUrlAuthenticationFailureHandler())
                 .and()
                 .logout()
            return httpSecurity.build()
        }
    
    }