diff --git a/config/src/main/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDsl.kt b/config/src/main/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDsl.kt index 57260b3d96..b663f4d717 100644 --- a/config/src/main/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDsl.kt @@ -16,6 +16,7 @@ package org.springframework.security.config.web.server +import org.springframework.security.authentication.ReactiveAuthenticationManager import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher @@ -57,10 +58,13 @@ operator fun ServerHttpSecurity.invoke(httpConfiguration: ServerHttpSecurityDsl. * @author Eleftheria Stein * @since 5.4 * @param init the configurations to apply to the provided [ServerHttpSecurity] + * @property authenticationManager the default [ReactiveAuthenticationManager] to use */ @ServerSecurityMarker class ServerHttpSecurityDsl(private val http: ServerHttpSecurity, private val init: ServerHttpSecurityDsl.() -> Unit) { + var authenticationManager: ReactiveAuthenticationManager? = null + /** * Allows configuring the [ServerHttpSecurity] to only be invoked when matching the * provided [ServerWebExchangeMatcher]. @@ -630,6 +634,7 @@ class ServerHttpSecurityDsl(private val http: ServerHttpSecurity, private val in */ internal fun build(): SecurityWebFilterChain { init() + authenticationManager?.also { this.http.authenticationManager(authenticationManager) } return this.http.build() } } diff --git a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt index 2128c9c9d4..2b8361b71c 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/server/ServerHttpSecurityDslTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,9 @@ package org.springframework.security.config.web.server +import io.mockk.every +import io.mockk.mockkObject +import io.mockk.verify import org.assertj.core.api.Assertions.assertThat import org.junit.Rule import org.junit.Test @@ -23,6 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.ApplicationContext import org.springframework.context.annotation.Bean import org.springframework.http.HttpHeaders +import org.springframework.security.authentication.ReactiveAuthenticationManager +import org.springframework.security.authentication.TestingAuthenticationToken import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity import org.springframework.security.config.test.SpringTestRule import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter @@ -199,4 +204,36 @@ class ServerHttpSecurityDslTests { class CustomWebFilter : WebFilter { override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono = Mono.empty() } + + @Test + fun `authentication manager when configured in DSL then used`() { + this.spring.register(AuthenticationManagerConfig::class.java).autowire() + mockkObject(AuthenticationManagerConfig.AUTHENTICATION_MANAGER) + every { + AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()) + } returns Mono.just(TestingAuthenticationToken("user", "password", "ROLE_USER")) + this.client.get().uri("/").headers { headers -> + headers.setBasicAuth("user", "password") + }.exchange() + verify(exactly = 1) { AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()) } + } + + @EnableWebFlux + @EnableWebFluxSecurity + open class AuthenticationManagerConfig { + companion object { + val AUTHENTICATION_MANAGER: ReactiveAuthenticationManager = ReactiveAuthenticationManager { Mono.empty() } + } + + @Bean + open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http { + authenticationManager = AUTHENTICATION_MANAGER + authorizeExchange { + authorize(anyExchange, authenticated) + } + httpBasic { } + } + } + } }