Skip to content

Commit a7f9ccb

Browse files
committed
Use GrantedAuthorityDefaults Bean in Kotlin DSL
Closes gh-15171
1 parent 24e3bb1 commit a7f9ccb

File tree

3 files changed

+65
-8
lines changed

3 files changed

+65
-8
lines changed

config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDsl.kt

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@
1616

1717
package org.springframework.security.config.annotation.web
1818

19+
import org.springframework.context.ApplicationContext
1920
import org.springframework.http.HttpMethod
2021
import org.springframework.security.authorization.AuthenticatedAuthorizationManager
2122
import org.springframework.security.authorization.AuthorityAuthorizationManager
2223
import org.springframework.security.authorization.AuthorizationDecision
2324
import org.springframework.security.authorization.AuthorizationManager
2425
import org.springframework.security.config.annotation.web.builders.HttpSecurity
2526
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer
27+
import org.springframework.security.config.core.GrantedAuthorityDefaults
2628
import org.springframework.security.core.Authentication
29+
import org.springframework.security.web.access.IpAddressAuthorizationManager
2730
import org.springframework.security.web.access.intercept.AuthorizationFilter
2831
import org.springframework.security.web.access.intercept.RequestAuthorizationContext
29-
import org.springframework.security.web.access.IpAddressAuthorizationManager
3032
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher
3133
import org.springframework.security.web.util.matcher.AnyRequestMatcher
3234
import org.springframework.security.web.util.matcher.RequestMatcher
@@ -41,7 +43,7 @@ import java.util.function.Supplier
4143
* @since 5.7
4244
* @property shouldFilterAllDispatcherTypes whether the [AuthorizationFilter] should filter all dispatcher types
4345
*/
44-
class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
46+
class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl {
4547
@Deprecated("""
4648
Add authorization rules to DispatcherType directly.
4749
@@ -62,6 +64,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
6264
var shouldFilterAllDispatcherTypes: Boolean? = null
6365

6466
private val authorizationRules = mutableListOf<AuthorizationManagerRule>()
67+
private val rolePrefix: String
6568

6669
private val HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"
6770
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
@@ -227,7 +230,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
227230
* @return the [AuthorizationManager] with the provided role
228231
*/
229232
fun hasRole(role: String): AuthorizationManager<RequestAuthorizationContext> {
230-
return AuthorityAuthorizationManager.hasRole(role)
233+
return AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, arrayOf(role))
231234
}
232235

233236
/**
@@ -237,7 +240,7 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
237240
* @return the [AuthorizationManager] with the provided roles
238241
*/
239242
fun hasAnyRole(vararg roles: String): AuthorizationManager<RequestAuthorizationContext> {
240-
return AuthorityAuthorizationManager.hasAnyRole(*roles)
243+
return AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, arrayOf(*roles))
241244
}
242245

243246
/**
@@ -290,4 +293,18 @@ class AuthorizeHttpRequestsDsl : AbstractRequestMatcherDsl() {
290293
}
291294
}
292295
}
296+
297+
constructor() {
298+
this.rolePrefix = "ROLE_"
299+
}
300+
301+
constructor(context: ApplicationContext) {
302+
val beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults::class.java)
303+
if (beanNames.size > 0) {
304+
val grantedAuthorityDefaults = context.getBean(GrantedAuthorityDefaults::class.java);
305+
this.rolePrefix = grantedAuthorityDefaults.rolePrefix
306+
} else {
307+
this.rolePrefix = "ROLE_"
308+
}
309+
}
293310
}

config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
7777
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
7878

7979
var authenticationManager: AuthenticationManager? = null
80+
val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java)
8081

8182
/**
8283
* Applies a [SecurityConfigurerAdapter] to this [HttpSecurity]
@@ -298,7 +299,7 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
298299
* @since 5.7
299300
*/
300301
fun authorizeHttpRequests(authorizeHttpRequestsConfiguration: AuthorizeHttpRequestsDsl.() -> Unit) {
301-
val authorizeHttpRequestsCustomizer = AuthorizeHttpRequestsDsl().apply(authorizeHttpRequestsConfiguration).get()
302+
val authorizeHttpRequestsCustomizer = AuthorizeHttpRequestsDsl(this.context).apply(authorizeHttpRequestsConfiguration).get()
302303
this.http.authorizeHttpRequests(authorizeHttpRequestsCustomizer)
303304
}
304305

config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeHttpRequestsDslTests.kt

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
package org.springframework.security.config.annotation.web
1818

19-
import org.assertj.core.api.Assertions.*
19+
import jakarta.servlet.DispatcherType
20+
import org.assertj.core.api.Assertions.assertThatThrownBy
2021
import org.junit.jupiter.api.Test
2122
import org.junit.jupiter.api.extension.ExtendWith
2223
import org.springframework.beans.factory.UnsatisfiedDependencyException
@@ -28,6 +29,7 @@ import org.springframework.security.authorization.AuthorizationDecision
2829
import org.springframework.security.authorization.AuthorizationManager
2930
import org.springframework.security.config.annotation.web.builders.HttpSecurity
3031
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
32+
import org.springframework.security.config.core.GrantedAuthorityDefaults
3133
import org.springframework.security.config.test.SpringTestContext
3234
import org.springframework.security.config.test.SpringTestContextExtension
3335
import org.springframework.security.core.Authentication
@@ -55,7 +57,6 @@ import org.springframework.web.servlet.config.annotation.PathMatchConfigurer
5557
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
5658
import org.springframework.web.util.WebUtils
5759
import java.util.function.Supplier
58-
import jakarta.servlet.DispatcherType
5960

6061
/**
6162
* Tests for [AuthorizeHttpRequestsDsl]
@@ -835,7 +836,6 @@ class AuthorizeHttpRequestsDslTests {
835836
@EnableWebSecurity
836837
@EnableWebMvc
837838
open class HasIpAddressConfig {
838-
839839
@Bean
840840
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
841841
http {
@@ -853,4 +853,43 @@ class AuthorizeHttpRequestsDslTests {
853853
}
854854
}
855855
}
856+
857+
fun `hasRole when prefixed by configured role prefix should fail to configure`() {
858+
assertThatThrownBy { this.spring.register(RoleValidationConfig::class.java).autowire() }
859+
.isInstanceOf(UnsatisfiedDependencyException::class.java)
860+
.hasRootCauseInstanceOf(IllegalArgumentException::class.java)
861+
.hasMessageContaining(
862+
"ROLE_JUNIPER should not start with ROLE_ since ROLE_ is automatically prepended when using hasAnyRole. Consider using hasAnyAuthority instead."
863+
)
864+
assertThatThrownBy { this.spring.register(RoleValidationConfig::class.java, GrantedAuthorityDefaultsConfig::class.java).autowire() }
865+
.isInstanceOf(UnsatisfiedDependencyException::class.java)
866+
.hasRootCauseInstanceOf(IllegalArgumentException::class.java)
867+
.hasMessageContaining(
868+
"CUSTOM_JUNIPER should not start with CUSTOM_ since CUSTOM_ is automatically prepended when using hasAnyRole. Consider using hasAnyAuthority instead."
869+
)
870+
}
871+
872+
@Configuration
873+
@EnableWebSecurity
874+
@EnableWebMvc
875+
open class RoleValidationConfig {
876+
@Bean
877+
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
878+
http {
879+
authorizeHttpRequests {
880+
authorize("/role", hasAnyRole("ROLE_JUNIPER"))
881+
authorize("/custom", hasRole("CUSTOM_JUNIPER"))
882+
}
883+
}
884+
return http.build()
885+
}
886+
}
887+
888+
@Configuration
889+
open class GrantedAuthorityDefaultsConfig {
890+
@Bean
891+
open fun grantedAuthorityDefaults(): GrantedAuthorityDefaults {
892+
return GrantedAuthorityDefaults("CUSTOM_")
893+
}
894+
}
856895
}

0 commit comments

Comments
 (0)