Support RoleHierarchy Bean in authorizeHttpRequests Kotlin DSL
Closes gh-15136
This commit is contained in:
parent
ed2b654f71
commit
7c43fc111f
|
@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.web
|
|||
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy
|
||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager
|
||||
import org.springframework.security.authorization.AuthorizationDecision
|
||||
|
@ -65,6 +67,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
|
||||
private val authorizationRules = mutableListOf<AuthorizationManagerRule>()
|
||||
private val rolePrefix: String
|
||||
private val roleHierarchy: RoleHierarchy
|
||||
|
||||
private val HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"
|
||||
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
|
||||
|
@ -210,7 +213,8 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
* @return the [AuthorizationManager] with the provided authority
|
||||
*/
|
||||
fun hasAuthority(authority: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAuthority(authority)
|
||||
val manager = AuthorityAuthorizationManager.hasAuthority<RequestAuthorizationContext>(authority)
|
||||
return withRoleHierarchy(manager)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,7 +224,8 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
* @return the [AuthorizationManager] with the provided authorities
|
||||
*/
|
||||
fun hasAnyAuthority(vararg authorities: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAnyAuthority(*authorities)
|
||||
val manager = AuthorityAuthorizationManager.hasAnyAuthority<RequestAuthorizationContext>(*authorities)
|
||||
return withRoleHierarchy(manager)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,7 +235,8 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
* @return the [AuthorizationManager] with the provided role
|
||||
*/
|
||||
fun hasRole(role: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, arrayOf(role))
|
||||
val manager = AuthorityAuthorizationManager.hasAnyRole<RequestAuthorizationContext>(this.rolePrefix, arrayOf(role))
|
||||
return withRoleHierarchy(manager)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -240,7 +246,8 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
* @return the [AuthorizationManager] with the provided roles
|
||||
*/
|
||||
fun hasAnyRole(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
|
||||
return AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, arrayOf(*roles))
|
||||
val manager = AuthorityAuthorizationManager.hasAnyRole<RequestAuthorizationContext>(this.rolePrefix, arrayOf(*roles))
|
||||
return withRoleHierarchy(manager)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -296,15 +303,34 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
|
|||
|
||||
constructor() {
|
||||
this.rolePrefix = "ROLE_"
|
||||
this.roleHierarchy = NullRoleHierarchy()
|
||||
}
|
||||
|
||||
constructor(context: ApplicationContext) {
|
||||
val rolePrefix = resolveRolePrefix(context)
|
||||
this.rolePrefix = rolePrefix
|
||||
val roleHierarchy = resolveRoleHierarchy(context)
|
||||
this.roleHierarchy = roleHierarchy
|
||||
}
|
||||
|
||||
private fun resolveRolePrefix(context: ApplicationContext): String {
|
||||
val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java)
|
||||
if (beanNames.size > 0) {
|
||||
val grantedAuthorityDefaults = context.getBean(GrantedAuthorityDefaults::class.java);
|
||||
this.rolePrefix = grantedAuthorityDefaults.rolePrefix
|
||||
} else {
|
||||
this.rolePrefix = "ROLE_"
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(GrantedAuthorityDefaults::class.java).rolePrefix
|
||||
}
|
||||
return "ROLE_";
|
||||
}
|
||||
|
||||
private fun resolveRoleHierarchy(context: ApplicationContext): RoleHierarchy {
|
||||
val beanNames = context.getBeanNamesForType(RoleHierarchy::class.java)
|
||||
if (beanNames.isNotEmpty()) {
|
||||
return context.getBean(RoleHierarchy::class.java)
|
||||
}
|
||||
return NullRoleHierarchy()
|
||||
}
|
||||
|
||||
private fun withRoleHierarchy(manager: AuthorityAuthorizationManager<RequestAuthorizationContext>): AuthorityAuthorizationManager<RequestAuthorizationContext> {
|
||||
manager.setRoleHierarchy(this.roleHierarchy)
|
||||
return manager
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -25,6 +25,8 @@ 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.access.hierarchicalroles.RoleHierarchy
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl
|
||||
import org.springframework.security.authorization.AuthorizationDecision
|
||||
import org.springframework.security.authorization.AuthorizationManager
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
|
@ -892,4 +894,70 @@ class AuthorizeHttpRequestsDslTests {
|
|||
return GrantedAuthorityDefaults("CUSTOM_")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasRole when role hierarchy configured then honor hierarchy`() {
|
||||
this.spring.register(RoleHierarchyConfig::class.java).autowire()
|
||||
this.mockMvc.get("/protected") {
|
||||
with(httpBasic("admin", "password"))
|
||||
}.andExpect {
|
||||
status {
|
||||
isOk()
|
||||
}
|
||||
}
|
||||
this.mockMvc.get("/protected") {
|
||||
with(httpBasic("user", "password"))
|
||||
}.andExpect {
|
||||
status {
|
||||
isOk()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
open class RoleHierarchyConfig {
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize("/protected", hasRole("USER"))
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun roleHierarchy(): RoleHierarchy {
|
||||
return RoleHierarchyImpl.fromHierarchy("ROLE_ADMIN > ROLE_USER")
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService {
|
||||
val user = User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
val admin = User.withDefaultPasswordEncoder()
|
||||
.username("admin")
|
||||
.password("password")
|
||||
.roles("ADMIN")
|
||||
.build()
|
||||
return InMemoryUserDetailsManager(user, admin)
|
||||
}
|
||||
|
||||
@RestController
|
||||
internal class PathController {
|
||||
|
||||
@RequestMapping("/protected")
|
||||
fun path() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,3 +5,5 @@ Spring Security 6.4 provides a number of new features.
|
|||
Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix.
|
||||
|
||||
- https://github.com/spring-projects/spring-security/issues/4186[gh-4186] - Support `RoleHierarchy` in `AclAuthorizationStrategyImpl`
|
||||
- https://github.com/spring-projects/spring-security/issues/15136[gh-15136] - Support `RoleHierarchy` Bean in `authorizeHttpRequests` Kotlin DSL
|
||||
|
||||
|
|
Loading…
Reference in New Issue