Add authorizeHttpRequests to Kotlin DSL
Closes gh-10481
This commit is contained in:
committed by
Josh Cummings
parent
932ff4f5c4
commit
ca00b1415b
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import org.assertj.core.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.UnsatisfiedDependencyException
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.authorization.AuthorizationDecision
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
import org.springframework.security.web.util.matcher.RegexRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.put
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
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 java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* Tests for [AuthorizeHttpRequestsDsl]
|
||||
*
|
||||
* @author Yuriy Savchenko
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class AuthorizeHttpRequestsDslTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `request when secured by regex matcher then responds with forbidden`() {
|
||||
this.spring.register(AuthorizeHttpRequestsByRegexConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/private")
|
||||
.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when allowed by regex matcher then responds with ok`() {
|
||||
this.spring.register(AuthorizeHttpRequestsByRegexConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when allowed by regex matcher with http method then responds based on method`() {
|
||||
this.spring.register(AuthorizeHttpRequestsByRegexConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.post("/onlyPostPermitted") { with(csrf()) }
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/onlyPostPermitted")
|
||||
.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthorizeHttpRequestsByRegexConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(RegexRequestMatcher("/path", null), permitAll)
|
||||
authorize(RegexRequestMatcher("/onlyPostPermitted", "POST"), permitAll)
|
||||
authorize(RegexRequestMatcher("/onlyPostPermitted", "GET"), denyAll)
|
||||
authorize(RegexRequestMatcher(".*", null), authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
|
||||
@RequestMapping("/onlyPostPermitted")
|
||||
fun onlyPostPermitted() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc then responds with forbidden`() {
|
||||
this.spring.register(AuthorizeHttpRequestsByMvcConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/private")
|
||||
.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when allowed by mvc then responds with OK`() {
|
||||
this.spring.register(AuthorizeHttpRequestsByMvcConfig::class.java, LegacyMvcMatchingConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path.html")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/path/")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AuthorizeHttpRequestsByMvcConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/path", permitAll)
|
||||
authorize("/**", authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class LegacyMvcMatchingConfig : WebMvcConfigurer {
|
||||
override fun configurePathMatch(configurer: PathMatchConfigurer) {
|
||||
configurer.setUseSuffixPatternMatch(true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc path variables then responds based on path variable value`() {
|
||||
this.spring.register(MvcMatcherPathVariablesConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/user/user")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/user/deny")
|
||||
.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherPathVariablesConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
val access = AuthorizationManager { _: Supplier<Authentication>, context: RequestAuthorizationContext ->
|
||||
AuthorizationDecision(context.variables["userName"] == "user")
|
||||
}
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/user/{userName}", access)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/user/{user}")
|
||||
fun path(@PathVariable user: String) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user has allowed role then responds with OK`() {
|
||||
this.spring.register(HasRoleConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("admin", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user does not have allowed role then responds with forbidden`() {
|
||||
this.spring.register(HasRoleConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class HasRoleConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/**", hasRole("ADMIN"))
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@GetMapping("/")
|
||||
fun index() {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val adminDetails = User.withDefaultPasswordEncoder()
|
||||
.username("admin")
|
||||
.password("password")
|
||||
.roles("ADMIN")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails, adminDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user has some allowed roles then responds with OK`() {
|
||||
this.spring.register(HasAnyRoleConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("admin", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user does not have any allowed roles then responds with forbidden`() {
|
||||
this.spring.register(HasAnyRoleConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("other", "password"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class HasAnyRoleConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/**", hasAnyRole("ADMIN", "USER"))
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@GetMapping("/")
|
||||
fun index() {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val admin1Details = User.withDefaultPasswordEncoder()
|
||||
.username("admin")
|
||||
.password("password")
|
||||
.roles("ADMIN")
|
||||
.build()
|
||||
val admin2Details = User.withDefaultPasswordEncoder()
|
||||
.username("other")
|
||||
.password("password")
|
||||
.roles("OTHER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails, admin1Details, admin2Details)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user has allowed authority then responds with OK`() {
|
||||
this.spring.register(HasAuthorityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("admin", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user does not have allowed authority then responds with forbidden`() {
|
||||
this.spring.register(HasAuthorityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class HasAuthorityConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/**", hasAuthority("ROLE_ADMIN"))
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@GetMapping("/")
|
||||
fun index() {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val adminDetails = User.withDefaultPasswordEncoder()
|
||||
.username("admin")
|
||||
.password("password")
|
||||
.roles("ADMIN")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails, adminDetails)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user has some allowed authorities then responds with OK`() {
|
||||
this.spring.register(HasAnyAuthorityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("admin", "password"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when user does not have any allowed authorities then responds with forbidden`() {
|
||||
this.spring.register(HasAnyAuthorityConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/") {
|
||||
with(httpBasic("other", "password"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class HasAnyAuthorityConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/**", hasAnyAuthority("ROLE_ADMIN", "ROLE_USER"))
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@GetMapping("/")
|
||||
fun index() {
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val userDetails = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.authorities("ROLE_USER")
|
||||
.build()
|
||||
val admin1Details = User.withDefaultPasswordEncoder()
|
||||
.username("admin")
|
||||
.password("password")
|
||||
.authorities("ROLE_ADMIN")
|
||||
.build()
|
||||
val admin2Details = User.withDefaultPasswordEncoder()
|
||||
.username("other")
|
||||
.password("password")
|
||||
.authorities("ROLE_OTHER")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(userDetails, admin1Details, admin2Details)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc with servlet path then responds based on servlet path`() {
|
||||
this.spring.register(MvcMatcherServletPathConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(get("/spring/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/spring"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isForbidden)
|
||||
|
||||
this.mockMvc.perform(get("/other/path")
|
||||
.with { request ->
|
||||
request.servletPath = "/other"
|
||||
request
|
||||
})
|
||||
.andExpect(status().isOk)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherServletPathConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/path", "/spring", denyAll)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc with http method then responds based on http method`() {
|
||||
this.spring.register(AuthorizeRequestsByMvcConfigWithHttpMethod::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
|
||||
this.mockMvc.put("/path") { with(csrf()) }
|
||||
.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class AuthorizeRequestsByMvcConfigWithHttpMethod {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(HttpMethod.GET, "/path", permitAll)
|
||||
authorize(HttpMethod.PUT, "/path", denyAll)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when secured by mvc with servlet path and http method then responds based on path and method`() {
|
||||
this.spring.register(MvcMatcherServletPathHttpMethodConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.perform(get("/spring/path")
|
||||
.with { request ->
|
||||
request.apply {
|
||||
servletPath = "/spring"
|
||||
}
|
||||
})
|
||||
.andExpect(status().isForbidden)
|
||||
|
||||
this.mockMvc.perform(put("/spring/path")
|
||||
.with { request ->
|
||||
request.apply {
|
||||
servletPath = "/spring"
|
||||
csrf()
|
||||
}
|
||||
})
|
||||
.andExpect(status().isForbidden)
|
||||
|
||||
this.mockMvc.perform(get("/other/path")
|
||||
.with { request ->
|
||||
request.apply {
|
||||
servletPath = "/other"
|
||||
}
|
||||
})
|
||||
.andExpect(status().isOk)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MvcMatcherServletPathHttpMethodConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(HttpMethod.GET, "/path", "/spring", denyAll)
|
||||
authorize(HttpMethod.PUT, "/path", "/spring", denyAll)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
@RequestMapping("/path")
|
||||
fun path() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when both authorizeRequests and authorizeHttpRequests configured then exception`() {
|
||||
assertThatThrownBy { this.spring.register(BothAuthorizeRequestsConfig::class.java).autowire() }
|
||||
.isInstanceOf(UnsatisfiedDependencyException::class.java)
|
||||
.hasRootCauseInstanceOf(IllegalStateException::class.java)
|
||||
.hasMessageContaining(
|
||||
"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one."
|
||||
)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class BothAuthorizeRequestsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, permitAll)
|
||||
}
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, denyAll)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -53,6 +53,9 @@ import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
import jakarta.servlet.Filter
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
|
||||
/**
|
||||
* Tests for [HttpSecurityDsl]
|
||||
@@ -128,9 +131,13 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it does not match the security request matcher then the security rules do not apply`() {
|
||||
this.spring.register(SecurityRequestMatcherConfig::class.java).autowire()
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
SecurityRequestMatcherRequestsConfig::class,
|
||||
SecurityRequestMatcherHttpRequestsConfig::class
|
||||
])
|
||||
fun `request when it does not match the security request matcher then the security rules do not apply`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
@@ -138,9 +145,13 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it matches the security request matcher then the security rules apply`() {
|
||||
this.spring.register(SecurityRequestMatcherConfig::class.java).autowire()
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
SecurityRequestMatcherRequestsConfig::class,
|
||||
SecurityRequestMatcherHttpRequestsConfig::class
|
||||
])
|
||||
fun `request when it matches the security request matcher then the security rules apply`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
@@ -149,7 +160,7 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class SecurityRequestMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
open class SecurityRequestMatcherRequestsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher(RegexRequestMatcher("/path", null))
|
||||
@@ -160,9 +171,27 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it does not match the security pattern matcher then the security rules do not apply`() {
|
||||
this.spring.register(SecurityPatternMatcherConfig::class.java).autowire()
|
||||
@EnableWebSecurity
|
||||
open class SecurityRequestMatcherHttpRequestsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
securityMatcher(RegexRequestMatcher("/path", null))
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
SecurityPatternMatcherRequestsConfig::class,
|
||||
SecurityPatternMatcherHttpRequestsConfig::class
|
||||
])
|
||||
fun `request when it does not match the security pattern matcher then the security rules do not apply`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
@@ -170,9 +199,13 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when it matches the security pattern matcher then the security rules apply`() {
|
||||
this.spring.register(SecurityPatternMatcherConfig::class.java).autowire()
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
SecurityPatternMatcherRequestsConfig::class,
|
||||
SecurityPatternMatcherHttpRequestsConfig::class
|
||||
])
|
||||
fun `request when it matches the security pattern matcher then the security rules apply`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
|
||||
this.mockMvc.get("/path")
|
||||
.andExpect {
|
||||
@@ -182,7 +215,7 @@ class HttpSecurityDslTests {
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class SecurityPatternMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
open class SecurityPatternMatcherRequestsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher("/path")
|
||||
@@ -193,9 +226,28 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `security pattern matcher when used with security request matcher then both apply`() {
|
||||
this.spring.register(MultiMatcherConfig::class.java).autowire()
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class SecurityPatternMatcherHttpRequestsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
securityMatcher("/path")
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
MultiMatcherRequestsConfig::class,
|
||||
MultiMatcherHttpRequestsConfig::class
|
||||
])
|
||||
fun `security pattern matcher when used with security request matcher then both apply`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
|
||||
this.mockMvc.get("/path1")
|
||||
.andExpect {
|
||||
@@ -215,7 +267,7 @@ class HttpSecurityDslTests {
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MultiMatcherConfig : WebSecurityConfigurerAdapter() {
|
||||
open class MultiMatcherRequestsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
securityMatcher("/path1")
|
||||
@@ -227,28 +279,48 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `authentication manager when configured in DSL then used`() {
|
||||
this.spring.register(AuthenticationManagerConfig::class.java).autowire()
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class MultiMatcherHttpRequestsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
securityMatcher("/path1")
|
||||
securityMatcher(RegexRequestMatcher("/path2", null))
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = [
|
||||
AuthenticationManagerRequestsConfig::class,
|
||||
AuthenticationManagerHttpRequestsConfig::class
|
||||
])
|
||||
fun `authentication manager when configured in DSL then used`(config: Class<*>) {
|
||||
this.spring.register(config).autowire()
|
||||
mockkObject(AuthenticationManagerConfig.AUTHENTICATION_MANAGER)
|
||||
every {
|
||||
AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any())
|
||||
} returns TestingAuthenticationToken("user", "test", "ROLE_USER")
|
||||
val request = MockMvcRequestBuilders.get("/")
|
||||
val request = MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
this.mockMvc.perform(request)
|
||||
verify(exactly = 1) { AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()) }
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthenticationManagerConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
val AUTHENTICATION_MANAGER: AuthenticationManager = ProviderManager(TestingAuthenticationProvider())
|
||||
}
|
||||
object AuthenticationManagerConfig {
|
||||
val AUTHENTICATION_MANAGER: AuthenticationManager = ProviderManager(TestingAuthenticationProvider())
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthenticationManagerRequestsConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authenticationManager = AUTHENTICATION_MANAGER
|
||||
authenticationManager = AuthenticationManagerConfig.AUTHENTICATION_MANAGER
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
@@ -257,6 +329,21 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthenticationManagerHttpRequestsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authenticationManager = AuthenticationManagerConfig.AUTHENTICATION_MANAGER
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `HTTP security when custom filter configured then custom filter added to filter chain`() {
|
||||
this.spring.register(CustomFilterConfig::class.java).autowire()
|
||||
|
||||
Reference in New Issue
Block a user