Skip to content

Commit cd50c81

Browse files
author
Peer Schönhusen
committed
Add reified function variants to security DSL
Closes gh-8697
1 parent d31fff1 commit cd50c81

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

config/src/main/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDsl.kt

+78
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
669669
this.http.addFilterAt(filter, atFilter)
670670
}
671671

672+
/**
673+
* Adds the [Filter] at the location of the specified [Filter] class.
674+
* Variant that is leveraging Kotlin reified type parameters.
675+
*
676+
* Example:
677+
*
678+
* ```
679+
* @EnableWebSecurity
680+
* class SecurityConfig : WebSecurityConfigurerAdapter() {
681+
*
682+
* override fun configure(http: HttpSecurity) {
683+
* http {
684+
* addFilterAt<UsernamePasswordAuthenticationFilter>(CustomFilter())
685+
* }
686+
* }
687+
* }
688+
* ```
689+
*
690+
* @param filter the [Filter] to register
691+
* @param T the location of another [Filter] that is already registered
692+
* (i.e. known) with Spring Security.
693+
*/
694+
inline fun <reified T: Filter> addFilterAt(filter: Filter) {
695+
this.addFilterAt(filter, T::class.java)
696+
}
697+
672698
/**
673699
* Adds the [Filter] after the location of the specified [Filter] class.
674700
*
@@ -694,6 +720,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
694720
this.http.addFilterAfter(filter, afterFilter)
695721
}
696722

723+
/**
724+
* Adds the [Filter] after the location of the specified [Filter] class.
725+
* Variant that is leveraging Kotlin reified type parameters.
726+
*
727+
* Example:
728+
*
729+
* ```
730+
* @EnableWebSecurity
731+
* class SecurityConfig : WebSecurityConfigurerAdapter() {
732+
*
733+
* override fun configure(http: HttpSecurity) {
734+
* http {
735+
* addFilterAfter<UsernamePasswordAuthenticationFilter>(CustomFilter())
736+
* }
737+
* }
738+
* }
739+
* ```
740+
*
741+
* @param filter the [Filter] to register
742+
* @param T the location of another [Filter] that is already registered
743+
* (i.e. known) with Spring Security.
744+
*/
745+
inline fun <reified T: Filter> addFilterAfter(filter: Filter) {
746+
this.addFilterAfter(filter, T::class.java)
747+
}
748+
697749
/**
698750
* Adds the [Filter] before the location of the specified [Filter] class.
699751
*
@@ -719,6 +771,32 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
719771
this.http.addFilterBefore(filter, beforeFilter)
720772
}
721773

774+
/**
775+
* Adds the [Filter] before the location of the specified [Filter] class.
776+
* Variant that is leveraging Kotlin reified type parameters.
777+
*
778+
* Example:
779+
*
780+
* ```
781+
* @EnableWebSecurity
782+
* class SecurityConfig : WebSecurityConfigurerAdapter() {
783+
*
784+
* override fun configure(http: HttpSecurity) {
785+
* http {
786+
* addFilterBefore<UsernamePasswordAuthenticationFilter>(CustomFilter())
787+
* }
788+
* }
789+
* }
790+
* ```
791+
*
792+
* @param filter the [Filter] to register
793+
* @param T the location of another [Filter] that is already registered
794+
* (i.e. known) with Spring Security.
795+
*/
796+
inline fun <reified T: Filter> addFilterBefore(filter: Filter) {
797+
this.addFilterBefore(filter, T::class.java)
798+
}
799+
722800
/**
723801
* Apply all configurations to the provided [HttpSecurity]
724802
*/

config/src/main/kotlin/org/springframework/security/config/web/servlet/oauth2/login/UserInfoEndpointDsl.kt

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ class UserInfoEndpointDsl {
5757
customUserTypePair = Pair(customUserType, clientRegistrationId)
5858
}
5959

60+
/**
61+
* Sets a custom [OAuth2User] type and associates it to the provided
62+
* client [ClientRegistration.getRegistrationId] registration identifier.
63+
* Variant that is leveraging Kotlin reified type parameters.
64+
*
65+
* @param T a custom [OAuth2User] type
66+
* @param clientRegistrationId the client registration identifier
67+
*/
68+
inline fun <reified T: OAuth2User> customUserType(clientRegistrationId: String) {
69+
customUserType(T::class.java, clientRegistrationId)
70+
}
71+
6072
internal fun get(): (OAuth2LoginConfigurer<HttpSecurity>.UserInfoEndpointConfig) -> Unit {
6173
return { userInfoEndpoint ->
6274
userService?.also { userInfoEndpoint.userService(userService) }

config/src/test/kotlin/org/springframework/security/config/web/servlet/HttpSecurityDslTests.kt

+69
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,27 @@ class HttpSecurityDslTests {
238238
}
239239
}
240240

241+
@Test
242+
fun `HTTP security when custom filter configured with reified variant then custom filter added to filter chain`() {
243+
this.spring.register(CustomFilterConfigReified::class.java).autowire()
244+
245+
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
246+
val filters: List<Filter> = filterChain.getFilters("/")
247+
248+
assertThat(filters).hasSize(1)
249+
assertThat(filters[0]).isExactlyInstanceOf(CustomFilter::class.java)
250+
}
251+
252+
@EnableWebSecurity
253+
@EnableWebMvc
254+
open class CustomFilterConfigReified : WebSecurityConfigurerAdapter(true) {
255+
override fun configure(http: HttpSecurity) {
256+
http {
257+
addFilterAt<UsernamePasswordAuthenticationFilter>(CustomFilter())
258+
}
259+
}
260+
}
261+
241262
@Test
242263
fun `HTTP security when custom filter configured then custom filter added after specific filter to filter chain`() {
243264
this.spring.register(CustomFilterAfterConfig::class.java).autowire()
@@ -262,6 +283,30 @@ class HttpSecurityDslTests {
262283
}
263284
}
264285

286+
@Test
287+
fun `HTTP security when custom filter configured with reified variant then custom filter added after specific filter to filter chain`() {
288+
this.spring.register(CustomFilterAfterConfigReified::class.java).autowire()
289+
290+
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
291+
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
292+
293+
assertThat(filterClasses).containsSubsequence(
294+
UsernamePasswordAuthenticationFilter::class.java,
295+
CustomFilter::class.java
296+
)
297+
}
298+
299+
@EnableWebSecurity
300+
@EnableWebMvc
301+
open class CustomFilterAfterConfigReified : WebSecurityConfigurerAdapter() {
302+
override fun configure(http: HttpSecurity) {
303+
http {
304+
addFilterAfter<UsernamePasswordAuthenticationFilter>(CustomFilter())
305+
formLogin { }
306+
}
307+
}
308+
}
309+
265310
@Test
266311
fun `HTTP security when custom filter configured then custom filter added before specific filter to filter chain`() {
267312
this.spring.register(CustomFilterBeforeConfig::class.java).autowire()
@@ -286,5 +331,29 @@ class HttpSecurityDslTests {
286331
}
287332
}
288333

334+
@Test
335+
fun `HTTP security when custom filter configured with reified variant then custom filter added before specific filter to filter chain`() {
336+
this.spring.register(CustomFilterBeforeConfigReified::class.java).autowire()
337+
338+
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
339+
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
340+
341+
assertThat(filterClasses).containsSubsequence(
342+
CustomFilter::class.java,
343+
UsernamePasswordAuthenticationFilter::class.java
344+
)
345+
}
346+
347+
@EnableWebSecurity
348+
@EnableWebMvc
349+
open class CustomFilterBeforeConfigReified : WebSecurityConfigurerAdapter() {
350+
override fun configure(http: HttpSecurity) {
351+
http {
352+
addFilterBefore<UsernamePasswordAuthenticationFilter>(CustomFilter())
353+
formLogin { }
354+
}
355+
}
356+
}
357+
289358
class CustomFilter : UsernamePasswordAuthenticationFilter()
290359
}

0 commit comments

Comments
 (0)