parent
3016ed0067
commit
446ab5047c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.security.config.web.servlet
|
||||
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
|
||||
|
@ -36,14 +38,25 @@ abstract class AbstractRequestMatcherDsl {
|
|||
protected data class MatcherAuthorizationRule(val matcher: RequestMatcher,
|
||||
override val rule: String) : AuthorizationRule(rule)
|
||||
|
||||
protected data class MatcherAuthorizationManagerRule(val matcher: RequestMatcher,
|
||||
override val rule: AuthorizationManager<RequestAuthorizationContext>) : AuthorizationManagerRule(rule)
|
||||
|
||||
protected data class PatternAuthorizationRule(val pattern: String,
|
||||
val patternType: PatternType,
|
||||
val servletPath: String? = null,
|
||||
val httpMethod: HttpMethod? = null,
|
||||
override val rule: String) : AuthorizationRule(rule)
|
||||
|
||||
protected data class PatternAuthorizationManagerRule(val pattern: String,
|
||||
val patternType: PatternType,
|
||||
val servletPath: String? = null,
|
||||
val httpMethod: HttpMethod? = null,
|
||||
override val rule: AuthorizationManager<RequestAuthorizationContext>) : AuthorizationManagerRule(rule)
|
||||
|
||||
protected abstract class AuthorizationRule(open val rule: String)
|
||||
|
||||
protected abstract class AuthorizationManagerRule(open val rule: AuthorizationManager<RequestAuthorizationContext>)
|
||||
|
||||
protected enum class PatternType {
|
||||
ANT, MVC
|
||||
}
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* 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.web.servlet
|
||||
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager
|
||||
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.configurers.AuthorizeHttpRequestsConfigurer
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
import org.springframework.util.ClassUtils
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure [HttpSecurity] request authorization using idiomatic Kotlin code.
|
||||
*
|
||||
* @author Yuriy Savchenko
|
||||
* @since 5.7
|
||||
*/
|
||||
class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
|
||||
private val authorizationRules = mutableListOf<AuthorizationManagerRule>()
|
||||
|
||||
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
|
||||
private val MVC_PRESENT = ClassUtils.isPresent(
|
||||
HANDLER_MAPPING_INTROSPECTOR,
|
||||
AuthorizeHttpRequestsDsl::class.java.classLoader)
|
||||
private val PATTERN_TYPE = if (MVC_PRESENT) PatternType.MVC else PatternType.ANT
|
||||
|
||||
/**
|
||||
* Adds a request authorization rule.
|
||||
*
|
||||
* @param matches the [RequestMatcher] to match incoming requests against
|
||||
* @param access the [AuthorizationManager] to secure the matching request
|
||||
* (i.e. created via hasAuthority("ROLE_USER"))
|
||||
*/
|
||||
fun authorize(matches: RequestMatcher = AnyRequestMatcher.INSTANCE,
|
||||
access: AuthorizationManager<RequestAuthorizationContext>) {
|
||||
authorizationRules.add(MatcherAuthorizationManagerRule(matches, access))
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request authorization rule for an endpoint matching the provided
|
||||
* pattern.
|
||||
* If Spring MVC is on the classpath, it will use an MVC matcher.
|
||||
* If Spring MVC is not on the classpath, it will use an ant matcher.
|
||||
* The MVC will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on
|
||||
* "/path", "/path/", "/path.html", etc.
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as an ant pattern will be used.
|
||||
*
|
||||
* @param pattern the pattern to match incoming requests against.
|
||||
* @param access the [AuthorizationManager] to secure the matching request
|
||||
* (i.e. created via hasAuthority("ROLE_USER"))
|
||||
*/
|
||||
fun authorize(pattern: String,
|
||||
access: AuthorizationManager<RequestAuthorizationContext>) {
|
||||
authorizationRules.add(
|
||||
PatternAuthorizationManagerRule(
|
||||
pattern = pattern,
|
||||
patternType = PATTERN_TYPE,
|
||||
rule = access
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request authorization rule for an endpoint matching the provided
|
||||
* pattern.
|
||||
* If Spring MVC is on the classpath, it will use an MVC matcher.
|
||||
* If Spring MVC is not on the classpath, it will use an ant matcher.
|
||||
* The MVC will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on
|
||||
* "/path", "/path/", "/path.html", etc.
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as an ant pattern will be used.
|
||||
*
|
||||
* @param method the HTTP method to match the income requests against.
|
||||
* @param pattern the pattern to match incoming requests against.
|
||||
* @param access the [AuthorizationManager] to secure the matching request
|
||||
* (i.e. created via hasAuthority("ROLE_USER"))
|
||||
*/
|
||||
fun authorize(method: HttpMethod,
|
||||
pattern: String,
|
||||
access: AuthorizationManager<RequestAuthorizationContext>) {
|
||||
authorizationRules.add(
|
||||
PatternAuthorizationManagerRule(
|
||||
pattern = pattern,
|
||||
patternType = PATTERN_TYPE,
|
||||
httpMethod = method,
|
||||
rule = access
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request authorization rule for an endpoint matching the provided
|
||||
* pattern.
|
||||
* If Spring MVC is on the classpath, it will use an MVC matcher.
|
||||
* If Spring MVC is not on the classpath, it will use an ant matcher.
|
||||
* The MVC will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on
|
||||
* "/path", "/path/", "/path.html", etc.
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as an ant pattern will be used.
|
||||
*
|
||||
* @param pattern the pattern to match incoming requests against.
|
||||
* @param servletPath the servlet path to match incoming requests against. This
|
||||
* only applies when using an MVC pattern matcher.
|
||||
* @param access the [AuthorizationManager] to secure the matching request
|
||||
* (i.e. created via hasAuthority("ROLE_USER"))
|
||||
*/
|
||||
fun authorize(pattern: String,
|
||||
servletPath: String,
|
||||
access: AuthorizationManager<RequestAuthorizationContext>) {
|
||||
authorizationRules.add(
|
||||
PatternAuthorizationManagerRule(
|
||||
pattern = pattern,
|
||||
patternType = PATTERN_TYPE,
|
||||
servletPath = servletPath,
|
||||
rule = access
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request authorization rule for an endpoint matching the provided
|
||||
* pattern.
|
||||
* If Spring MVC is on the classpath, it will use an MVC matcher.
|
||||
* If Spring MVC is not on the classpath, it will use an ant matcher.
|
||||
* The MVC will use the same rules that Spring MVC uses for matching.
|
||||
* For example, often times a mapping of the path "/path" will match on
|
||||
* "/path", "/path/", "/path.html", etc.
|
||||
* If the current request will not be processed by Spring MVC, a reasonable default
|
||||
* using the pattern as an ant pattern will be used.
|
||||
*
|
||||
* @param method the HTTP method to match the income requests against.
|
||||
* @param pattern the pattern to match incoming requests against.
|
||||
* @param servletPath the servlet path to match incoming requests against. This
|
||||
* only applies when using an MVC pattern matcher.
|
||||
* @param access the [AuthorizationManager] to secure the matching request
|
||||
* (i.e. created via hasAuthority("ROLE_USER"))
|
||||
*/
|
||||
fun authorize(method: HttpMethod,
|
||||
pattern: String,
|
||||
servletPath: String,
|
||||
access: AuthorizationManager<RequestAuthorizationContext>) {
|
||||
authorizationRules.add(
|
||||
PatternAuthorizationManagerRule(
|
||||
pattern = pattern,
|
||||
patternType = PATTERN_TYPE,
|
||||
servletPath = servletPath,
|
||||
httpMethod = method,
|
||||
rule = access
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require a particular authority.
|
||||
*
|
||||
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the [AuthorizationManager] with the provided authority
|
||||
*/
|
||||
fun hasAuthority(authority: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAuthority(authority)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require any of the provided authorities.
|
||||
*
|
||||
* @param authorities the authorities to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
|
||||
* @return the [AuthorizationManager] with the provided authorities
|
||||
*/
|
||||
fun hasAnyAuthority(vararg authorities: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAnyAuthority(*authorities)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require a particular role.
|
||||
*
|
||||
* @param role the role to require (i.e. USER, ADMIN, etc).
|
||||
* @return the [AuthorizationManager] with the provided role
|
||||
*/
|
||||
fun hasRole(role: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasRole(role)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs require any of the provided roles.
|
||||
*
|
||||
* @param roles the roles to require (i.e. USER, ADMIN, etc).
|
||||
* @return the [AuthorizationManager] with the provided roles
|
||||
*/
|
||||
fun hasAnyRole(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAnyRole(*roles)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by anyone.
|
||||
*/
|
||||
val permitAll: AuthorizationManager<RequestAuthorizationContext> =
|
||||
AuthorizationManager { _: Supplier<Authentication>, _: RequestAuthorizationContext -> AuthorizationDecision(true) }
|
||||
|
||||
/**
|
||||
* Specify that URLs are not allowed by anyone.
|
||||
*/
|
||||
val denyAll: AuthorizationManager<RequestAuthorizationContext> =
|
||||
AuthorizationManager { _: Supplier<Authentication>, _: RequestAuthorizationContext -> AuthorizationDecision(false) }
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by any authenticated user.
|
||||
*/
|
||||
val authenticated: AuthorizationManager<RequestAuthorizationContext> =
|
||||
AuthenticatedAuthorizationManager.authenticated()
|
||||
|
||||
internal fun get(): (AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry) -> Unit {
|
||||
return { requests ->
|
||||
authorizationRules.forEach { rule ->
|
||||
when (rule) {
|
||||
is MatcherAuthorizationManagerRule -> requests.requestMatchers(rule.matcher).access(rule.rule)
|
||||
is PatternAuthorizationManagerRule -> {
|
||||
when (rule.patternType) {
|
||||
PatternType.ANT -> requests.antMatchers(rule.httpMethod, rule.pattern).access(rule.rule)
|
||||
PatternType.MVC -> requests.mvcMatchers(rule.httpMethod, rule.pattern)
|
||||
.apply { if (rule.servletPath != null) servletPath(rule.servletPath) }
|
||||
.access(rule.rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,7 +101,10 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
|||
fun securityMatcher(vararg pattern: String) {
|
||||
val mvcPresent = ClassUtils.isPresent(
|
||||
HANDLER_MAPPING_INTROSPECTOR,
|
||||
AuthorizeRequestsDsl::class.java.classLoader)
|
||||
AuthorizeRequestsDsl::class.java.classLoader) ||
|
||||
ClassUtils.isPresent(
|
||||
HANDLER_MAPPING_INTROSPECTOR,
|
||||
AuthorizeHttpRequestsDsl::class.java.classLoader)
|
||||
this.http.requestMatchers {
|
||||
if (mvcPresent) {
|
||||
it.mvcMatchers(*pattern)
|
||||
|
@ -198,6 +201,38 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
|||
this.http.authorizeRequests(authorizeRequestsCustomizer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows restricting access based upon the [HttpServletRequest]
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* @EnableWebSecurity
|
||||
* class SecurityConfig {
|
||||
*
|
||||
* @Bean
|
||||
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
* http {
|
||||
* authorizeHttpRequests {
|
||||
* authorize("/public", permitAll)
|
||||
* authorize(anyRequest, authenticated)
|
||||
* }
|
||||
* }
|
||||
* return http.build()
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param authorizeHttpRequestsConfiguration custom configuration that specifies
|
||||
* access for requests
|
||||
* @see [AuthorizeHttpRequestsDsl]
|
||||
* @since 5.7
|
||||
*/
|
||||
fun authorizeHttpRequests(authorizeHttpRequestsConfiguration: AuthorizeHttpRequestsDsl.() -> Unit) {
|
||||
val authorizeHttpRequestsCustomizer = AuthorizeHttpRequestsDsl().apply(authorizeHttpRequestsConfiguration).get()
|
||||
this.http.authorizeHttpRequests(authorizeHttpRequestsCustomizer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables HTTP basic authentication.
|
||||
*
|
||||
|
|
|
@ -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.web.servlet
|
||||
|
||||
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 javax.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()
|
||||
|
|
Loading…
Reference in New Issue