Răsfoiți Sursa

Add reified function variants to security DSL

Closes gh-8697
Peer Schönhusen 5 ani în urmă
părinte
comite
3e25714dc6

+ 78 - 0
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)
         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<UsernamePasswordAuthenticationFilter>(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 <reified T: Filter> addFilterAt(filter: Filter) {
+        this.addFilterAt(filter, T::class.java)
+    }
+
     /**
     /**
      * Adds the [Filter] after the location of the specified [Filter] class.
      * 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)
         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<UsernamePasswordAuthenticationFilter>(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 <reified T: Filter> addFilterAfter(filter: Filter) {
+        this.addFilterAfter(filter, T::class.java)
+    }
+
     /**
     /**
      * Adds the [Filter] before the location of the specified [Filter] class.
      * 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)
         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<UsernamePasswordAuthenticationFilter>(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 <reified T: Filter> addFilterBefore(filter: Filter) {
+        this.addFilterBefore(filter, T::class.java)
+    }
+
     /**
     /**
      * Apply all configurations to the provided [HttpSecurity]
      * Apply all configurations to the provided [HttpSecurity]
      */
      */

+ 12 - 0
config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt

@@ -57,6 +57,18 @@ class UserInfoEndpointDsl {
         customUserTypePair = Pair(customUserType, clientRegistrationId)
         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 <reified T: OAuth2User> customUserType(clientRegistrationId: String) {
+        customUserType(T::class.java, clientRegistrationId)
+    }
+
     internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.UserInfoEndpointConfig) -> Unit {
     internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.UserInfoEndpointConfig) -> Unit {
         return { userInfoEndpoint ->
         return { userInfoEndpoint ->
             userService?.also { userInfoEndpoint.userService(userService) }
             userService?.also { userInfoEndpoint.userService(userService) }

+ 69 - 0
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<Filter> = 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<UsernamePasswordAuthenticationFilter>(CustomFilter())
+            }
+        }
+    }
+
     @Test
     @Test
     fun `HTTP security when custom filter configured then custom filter added after specific filter to filter chain`() {
     fun `HTTP security when custom filter configured then custom filter added after specific filter to filter chain`() {
         this.spring.register(CustomFilterAfterConfig::class.java).autowire()
         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<Class<out Filter>> = 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<UsernamePasswordAuthenticationFilter>(CustomFilter())
+                formLogin { }
+            }
+        }
+    }
+
     @Test
     @Test
     fun `HTTP security when custom filter configured then custom filter added before specific filter to filter chain`() {
     fun `HTTP security when custom filter configured then custom filter added before specific filter to filter chain`() {
         this.spring.register(CustomFilterBeforeConfig::class.java).autowire()
         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<Class<out Filter>> = 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<UsernamePasswordAuthenticationFilter>(CustomFilter())
+                formLogin { }
+            }
+        }
+    }
+
     class CustomFilter : UsernamePasswordAuthenticationFilter()
     class CustomFilter : UsernamePasswordAuthenticationFilter()
 }
 }