From cd50c810e623c6170fa2d6897224e23eef128c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peer=20Sch=C3=B6nhusen?= Date: Sun, 28 Jun 2020 16:26:53 +0200 Subject: [PATCH] Add reified function variants to security DSL Closes gh-8697 --- .../config/web/servlet/HttpSecurityDsl.kt | 78 +++++++++++++++++++ .../oauth2/login/UserInfoEndpointDsl.kt | 12 +++ .../web/servlet/HttpSecurityDslTests.kt | 69 ++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/config/src/main/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDsl.kt b/config/src/main/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDsl.kt index 492d5e1c5c6..137d459ce1c 100644 --- a/config/src/main/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDsl.kt @@ -669,6 +669,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu this.http.addFilterAt(filter, atFilter) } + /** + * Adds the [Filter] at the location of the specified [Filter] class. + * Variant that is leveraging Kotlin reified type parameters. + * + * Example: + * + * ``` + * @EnableWebSecurity + * class SecurityConfig : WebSecurityConfigurerAdapter() { + * + * override fun configure(http: HttpSecurity) { + * http { + * addFilterAt(CustomFilter()) + * } + * } + * } + * ``` + * + * @param filter the [Filter] to register + * @param T the location of another [Filter] that is already registered + * (i.e. known) with Spring Security. + */ + inline fun addFilterAt(filter: Filter) { + this.addFilterAt(filter, T::class.java) + } + /** * Adds the [Filter] after the location of the specified [Filter] class. * @@ -694,6 +720,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu this.http.addFilterAfter(filter, afterFilter) } + /** + * Adds the [Filter] after the location of the specified [Filter] class. + * Variant that is leveraging Kotlin reified type parameters. + * + * Example: + * + * ``` + * @EnableWebSecurity + * class SecurityConfig : WebSecurityConfigurerAdapter() { + * + * override fun configure(http: HttpSecurity) { + * http { + * addFilterAfter(CustomFilter()) + * } + * } + * } + * ``` + * + * @param filter the [Filter] to register + * @param T the location of another [Filter] that is already registered + * (i.e. known) with Spring Security. + */ + inline fun addFilterAfter(filter: Filter) { + this.addFilterAfter(filter, T::class.java) + } + /** * Adds the [Filter] before the location of the specified [Filter] class. * @@ -719,6 +771,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu this.http.addFilterBefore(filter, beforeFilter) } + /** + * Adds the [Filter] before the location of the specified [Filter] class. + * Variant that is leveraging Kotlin reified type parameters. + * + * Example: + * + * ``` + * @EnableWebSecurity + * class SecurityConfig : WebSecurityConfigurerAdapter() { + * + * override fun configure(http: HttpSecurity) { + * http { + * addFilterBefore(CustomFilter()) + * } + * } + * } + * ``` + * + * @param filter the [Filter] to register + * @param T the location of another [Filter] that is already registered + * (i.e. known) with Spring Security. + */ + inline fun addFilterBefore(filter: Filter) { + this.addFilterBefore(filter, T::class.java) + } + /** * Apply all configurations to the provided [HttpSecurity] */ diff --git a/config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt b/config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt index edddc41d799..3ef981e9584 100644 --- a/config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt @@ -57,6 +57,18 @@ class UserInfoEndpointDsl { customUserTypePair = Pair(customUserType, clientRegistrationId) } + /** + * Sets a custom [OAuth2User] type and associates it to the provided + * client [ClientRegistration.getRegistrationId] registration identifier. + * Variant that is leveraging Kotlin reified type parameters. + * + * @param T a custom [OAuth2User] type + * @param clientRegistrationId the client registration identifier + */ + inline fun customUserType(clientRegistrationId: String) { + customUserType(T::class.java, clientRegistrationId) + } + internal fun get(): (OAuth2LoginConfigurer.UserInfoEndpointConfig) -> Unit { return { userInfoEndpoint -> userService?.also { userInfoEndpoint.userService(userService) } diff --git a/config/src/test/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDslTests.kt index 83b1234f9d1..f603dff3a5b 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDslTests.kt @@ -238,6 +238,27 @@ class HttpSecurityDslTests { } } + @Test + fun `HTTP security when custom filter configured with reified variant then custom filter added to filter chain`() { + this.spring.register(CustomFilterConfigReified::class.java).autowire() + + val filterChain = spring.context.getBean(FilterChainProxy::class.java) + val filters: List = filterChain.getFilters("/") + + assertThat(filters).hasSize(1) + assertThat(filters[0]).isExactlyInstanceOf(CustomFilter::class.java) + } + + @EnableWebSecurity + @EnableWebMvc + open class CustomFilterConfigReified : WebSecurityConfigurerAdapter(true) { + override fun configure(http: HttpSecurity) { + http { + addFilterAt(CustomFilter()) + } + } + } + @Test fun `HTTP security when custom filter configured then custom filter added after specific filter to filter chain`() { this.spring.register(CustomFilterAfterConfig::class.java).autowire() @@ -262,6 +283,30 @@ class HttpSecurityDslTests { } } + @Test + fun `HTTP security when custom filter configured with reified variant then custom filter added after specific filter to filter chain`() { + this.spring.register(CustomFilterAfterConfigReified::class.java).autowire() + + val filterChain = spring.context.getBean(FilterChainProxy::class.java) + val filterClasses: List> = filterChain.getFilters("/").map { it.javaClass } + + assertThat(filterClasses).containsSubsequence( + UsernamePasswordAuthenticationFilter::class.java, + CustomFilter::class.java + ) + } + + @EnableWebSecurity + @EnableWebMvc + open class CustomFilterAfterConfigReified : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + addFilterAfter(CustomFilter()) + formLogin { } + } + } + } + @Test fun `HTTP security when custom filter configured then custom filter added before specific filter to filter chain`() { this.spring.register(CustomFilterBeforeConfig::class.java).autowire() @@ -286,5 +331,29 @@ class HttpSecurityDslTests { } } + @Test + fun `HTTP security when custom filter configured with reified variant then custom filter added before specific filter to filter chain`() { + this.spring.register(CustomFilterBeforeConfigReified::class.java).autowire() + + val filterChain = spring.context.getBean(FilterChainProxy::class.java) + val filterClasses: List> = filterChain.getFilters("/").map { it.javaClass } + + assertThat(filterClasses).containsSubsequence( + CustomFilter::class.java, + UsernamePasswordAuthenticationFilter::class.java + ) + } + + @EnableWebSecurity + @EnableWebMvc + open class CustomFilterBeforeConfigReified : WebSecurityConfigurerAdapter() { + override fun configure(http: HttpSecurity) { + http { + addFilterBefore(CustomFilter()) + formLogin { } + } + } + } + class CustomFilter : UsernamePasswordAuthenticationFilter() }