diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt index 4433f7ed397..31c41a42701 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt @@ -18,9 +18,11 @@ package org.springframework.security.config.annotation.web import org.springframework.context.ApplicationContext import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.config.annotation.SecurityConfigurerAdapter import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository +import org.springframework.security.web.DefaultSecurityFilterChain import org.springframework.security.web.util.matcher.RequestMatcher import org.springframework.util.ClassUtils import jakarta.servlet.Filter @@ -76,6 +78,35 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu var authenticationManager: AuthenticationManager? = null + /** + * Applies a [SecurityConfigurerAdapter] to this [HttpSecurity] + * + * Example: + * + * ``` + * @Configuration + * @EnableWebSecurity + * class SecurityConfig { + * + * @Bean + * fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + * http { + * apply(CustomSecurityConfigurer()) { + * customProperty = "..." + * } + * } + * return http.build() + * } + * } + * ``` + * + * @param configurer + * the [SecurityConfigurerAdapter] for further customizations + */ + fun > apply(configurer: C, configuration: C.() -> Unit = { }): C { + return this.http.apply(configurer).apply(configuration) + } + /** * Allows configuring the [HttpSecurity] to only be invoked when matching the * provided pattern. diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt index 2dc162ed48a..5669e9df3f8 100644 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDslTests.kt @@ -30,7 +30,9 @@ import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.ProviderManager import org.springframework.security.authentication.TestingAuthenticationProvider import org.springframework.security.authentication.TestingAuthenticationToken +import org.springframework.security.config.Customizer import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.test.SpringTestContext import org.springframework.security.config.test.SpringTestContextExtension @@ -516,4 +518,42 @@ class HttpSecurityDslTests { } class CustomFilter : UsernamePasswordAuthenticationFilter() + + @Test + fun `HTTP security when apply customer security configurer then custom filter added to filter chain`() { + this.spring.register(CustomSecurityConfigurerConfig::class.java).autowire() + + val filterChain = spring.context.getBean(FilterChainProxy::class.java) + val filterClasses: List> = filterChain.getFilters("/").map { it.javaClass } + + assertThat(filterClasses).contains( + CustomFilter::class.java + ) + } + + @Configuration + @EnableWebSecurity + @EnableWebMvc + open class CustomSecurityConfigurerConfig { + @Bean + open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + apply(CustomSecurityConfigurer()) { + filter = CustomFilter() + } + } + return http.build() + } + } + + class CustomSecurityConfigurer> : AbstractHttpConfigurer, H>() { + var filter: Filter? = null + override fun init(builder: H) { + filter = filter ?: UsernamePasswordAuthenticationFilter() + } + + override fun configure(builder: H) { + builder.addFilterBefore(CustomFilter(), UsernamePasswordAuthenticationFilter::class.java) + } + } }