Support custom filter in Server Kotlin DSL

Closes gh-8783
This commit is contained in:
Evgeniy Cheban 2020-07-19 15:22:44 +03:00 committed by Eleftheria Stein-Kousathana
parent b61bf49d07
commit 0a2006ebec
2 changed files with 152 additions and 0 deletions

View File

@ -20,6 +20,7 @@ import org.springframework.security.oauth2.client.registration.ReactiveClientReg
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilter
/**
* Configures [ServerHttpSecurity] using a [ServerHttpSecurity Kotlin DSL][ServerHttpSecurityDsl].
@ -89,6 +90,81 @@ class ServerHttpSecurityDsl(private val http: ServerHttpSecurity, private val in
this.http.securityMatcher(securityMatcher)
}
/**
* Adds a [WebFilter] at a specific position.
*
* Example:
*
* ```
* @EnableWebFluxSecurity
* class SecurityConfig {
*
* @Bean
* fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
* return http {
* addFilterAt(CustomWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
* }
* }
* }
* ```
*
* @param webFilter the [WebFilter] to add
* @param order the place to insert the [WebFilter]
*/
fun addFilterAt(webFilter: WebFilter, order: SecurityWebFiltersOrder) {
this.http.addFilterAt(webFilter, order)
}
/**
* Adds a [WebFilter] before specific position.
*
* Example:
*
* ```
* @EnableWebFluxSecurity
* class SecurityConfig {
*
* @Bean
* fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
* return http {
* addFilterBefore(CustomWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
* }
* }
* }
* ```
*
* @param webFilter the [WebFilter] to add
* @param order the place before which to insert the [WebFilter]
*/
fun addFilterBefore(webFilter: WebFilter, order: SecurityWebFiltersOrder) {
this.http.addFilterBefore(webFilter, order)
}
/**
* Adds a [WebFilter] after specific position.
*
* Example:
*
* ```
* @EnableWebFluxSecurity
* class SecurityConfig {
*
* @Bean
* fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
* return http {
* addFilterAfter(CustomWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
* }
* }
* }
* ```
*
* @param webFilter the [WebFilter] to add
* @param order the place after which to insert the [WebFilter]
*/
fun addFilterAfter(webFilter: WebFilter, order: SecurityWebFiltersOrder) {
this.http.addFilterAfter(webFilter, order)
}
/**
* Enables form based authentication.
*

View File

@ -16,6 +16,7 @@
package org.springframework.security.config.web.server
import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule
import org.junit.Test
import org.springframework.beans.factory.annotation.Autowired
@ -26,6 +27,7 @@ import org.springframework.security.config.annotation.web.reactive.EnableWebFlux
import org.springframework.security.config.test.SpringTestRule
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
@ -33,6 +35,10 @@ import org.springframework.security.web.server.header.XXssProtectionServerHttpHe
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.config.EnableWebFlux
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilter
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
/**
* Tests for [ServerHttpSecurityDsl]
@ -123,4 +129,74 @@ class ServerHttpSecurityDslTests {
}
}
}
@Test
fun `add filter at applies custom at specified filter position`() {
this.spring.register(CustomWebFilterAtConfig::class.java).autowire()
val filterChain = this.spring.context.getBean(SecurityWebFilterChain::class.java)
val filters = filterChain.webFilters.collectList().block()
assertThat(filters).last().isExactlyInstanceOf(CustomWebFilter::class.java)
}
@EnableWebFluxSecurity
@EnableWebFlux
open class CustomWebFilterAtConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
addFilterAt(CustomWebFilter(), SecurityWebFiltersOrder.LAST)
}
}
}
@Test
fun `add filter before applies custom before specified filter position`() {
this.spring.register(CustomWebFilterBeforeConfig::class.java).autowire()
val filterChain = this.spring.context.getBean(SecurityWebFilterChain::class.java)
val filters: List<Class<out WebFilter>>? = filterChain.webFilters.map { it.javaClass }.collectList().block()
assertThat(filters).containsSubsequence(
CustomWebFilter::class.java,
SecurityContextServerWebExchangeWebFilter::class.java
)
}
@EnableWebFluxSecurity
@EnableWebFlux
open class CustomWebFilterBeforeConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
addFilterBefore(CustomWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
}
}
}
@Test
fun `add filter after applies custom after specified filter position`() {
this.spring.register(CustomWebFilterAfterConfig::class.java).autowire()
val filterChain = this.spring.context.getBean(SecurityWebFilterChain::class.java)
val filters: List<Class<out WebFilter>>? = filterChain.webFilters.map { it.javaClass }.collectList().block()
assertThat(filters).containsSubsequence(
SecurityContextServerWebExchangeWebFilter::class.java,
CustomWebFilter::class.java
)
}
@EnableWebFluxSecurity
@EnableWebFlux
open class CustomWebFilterAfterConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
addFilterAfter(CustomWebFilter(), SecurityWebFiltersOrder.SECURITY_CONTEXT_SERVER_WEB_EXCHANGE)
}
}
}
class CustomWebFilter : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> = Mono.empty()
}
}