diff --git a/config/src/main/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDsl.kt b/config/src/main/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDsl.kt index 778380417b..f0ac9f4971 100644 --- a/config/src/main/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDsl.kt @@ -24,6 +24,7 @@ import org.springframework.security.authorization.AuthorizationManager import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer import org.springframework.security.core.Authentication +import org.springframework.security.web.access.intercept.AuthorizationFilter import org.springframework.security.web.access.intercept.RequestAuthorizationContext import org.springframework.security.web.util.matcher.AnyRequestMatcher import org.springframework.security.web.util.matcher.RequestMatcher @@ -35,8 +36,11 @@ import java.util.function.Supplier * * @author Yuriy Savchenko * @since 5.7 + * @property shouldFilterAllDispatcherTypes whether the [AuthorizationFilter] should filter all dispatcher types */ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() { + var shouldFilterAllDispatcherTypes: Boolean? = null + private val authorizationRules = mutableListOf() private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector" @@ -248,6 +252,9 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() { } } } + shouldFilterAllDispatcherTypes?.also { shouldFilter -> + requests.shouldFilterAllDispatcherTypes(shouldFilter) + } } } } diff --git a/config/src/test/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDslTests.kt index c919594710..95048a5a9d 100644 --- a/config/src/test/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDslTests.kt +++ b/config/src/test/kotlin/org/springframework/security/config/web/servlet/AuthorizeHttpRequestsDslTests.kt @@ -53,7 +53,9 @@ import org.springframework.web.bind.annotation.RestController import org.springframework.web.servlet.config.annotation.EnableWebMvc import org.springframework.web.servlet.config.annotation.PathMatchConfigurer import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import org.springframework.web.util.WebUtils import java.util.function.Supplier +import javax.servlet.DispatcherType /** * Tests for [AuthorizeHttpRequestsDsl] @@ -641,4 +643,155 @@ class AuthorizeHttpRequestsDslTests { return http.build() } } + + @Test + fun `request when shouldFilterAllDispatcherTypes and denyAll and ERROR then responds with forbidden`() { + this.spring.register(ShouldFilterAllDispatcherTypesTrueDenyAllConfig::class.java).autowire() + + this.mockMvc.perform(get("/path") + .with { request -> + request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error") + request.apply { + dispatcherType = DispatcherType.ERROR + } + }) + .andExpect(status().isForbidden) + } + + @EnableWebSecurity + @EnableWebMvc + open class ShouldFilterAllDispatcherTypesTrueDenyAllConfig { + + @Bean + open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + shouldFilterAllDispatcherTypes = true + authorize(anyRequest, denyAll) + } + } + return http.build() + } + + @RestController + internal class PathController { + @RequestMapping("/path") + fun path() { + } + } + + } + + @Test + fun `request when shouldFilterAllDispatcherTypes and permitAll and ERROR then responds with ok`() { + this.spring.register(ShouldFilterAllDispatcherTypesTruePermitAllConfig::class.java).autowire() + + this.mockMvc.perform(get("/path") + .with { request -> + request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error") + request.apply { + dispatcherType = DispatcherType.ERROR + } + }) + .andExpect(status().isOk) + } + + @EnableWebSecurity + @EnableWebMvc + open class ShouldFilterAllDispatcherTypesTruePermitAllConfig { + + @Bean + open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + shouldFilterAllDispatcherTypes = true + authorize(anyRequest, permitAll) + } + } + return http.build() + } + + @RestController + internal class PathController { + @RequestMapping("/path") + fun path() { + } + } + + } + + @Test + fun `request when shouldFilterAllDispatcherTypes false and ERROR dispatcher then responds with ok`() { + this.spring.register(ShouldFilterAllDispatcherTypesFalseAndDenyAllConfig::class.java).autowire() + + this.mockMvc.perform(get("/path") + .with { request -> + request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error") + request.apply { + dispatcherType = DispatcherType.ERROR + } + }) + .andExpect(status().isOk) + } + + @EnableWebSecurity + @EnableWebMvc + open class ShouldFilterAllDispatcherTypesFalseAndDenyAllConfig { + + @Bean + open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + shouldFilterAllDispatcherTypes = false + authorize(anyRequest, denyAll) + } + } + return http.build() + } + + @RestController + internal class PathController { + @RequestMapping("/path") + fun path() { + } + } + + } + + @Test + fun `request when shouldFilterAllDispatcherTypes omitted and ERROR dispatcher then responds with ok`() { + this.spring.register(ShouldFilterAllDispatcherTypesOmittedAndDenyAllConfig::class.java).autowire() + + this.mockMvc.perform(get("/path") + .with { request -> + request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error") + request.apply { + dispatcherType = DispatcherType.ERROR + } + }) + .andExpect(status().isOk) + } + + @EnableWebSecurity + @EnableWebMvc + open class ShouldFilterAllDispatcherTypesOmittedAndDenyAllConfig { + + @Bean + open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + authorize(anyRequest, denyAll) + } + } + return http.build() + } + + @RestController + internal class PathController { + @RequestMapping("/path") + fun path() { + } + } + + } } diff --git a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc index 0aea50e01d..d318f4d7be 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/authorize-http-requests.adoc @@ -190,4 +190,18 @@ SecurityFilterChain web(HttpSecurity http) throws Exception { return http.build(); } ---- +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +open fun web(http: HttpSecurity): SecurityFilterChain { + http { + authorizeHttpRequests { + shouldFilterAllDispatcherTypes = true + authorize(anyRequest, authenticated) + } + } + return http.build() +} +---- ====