Răsfoiți Sursa

Add hasAnyRole and hasAnyAuthority to authorizeRequests in Kotlin DSL

Closes gh-8892
koishikawa11 5 ani în urmă
părinte
comite
be6d2f117e

+ 24 - 0
config/src/main/kotlin/org/springframework/security/config/web/servlet/AuthorizeRequestsDsl.kt

@@ -153,6 +153,18 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
      */
     fun hasAuthority(authority: String) = "hasAuthority('$authority')"
 
+    /**
+     * Specify that URLs requires any of a number authorities.
+     *
+     * @param authorities the authorities to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
+     * @return the SpEL expression "hasAnyAuthority" with the given authorities as a
+     * parameter
+     */
+    fun hasAnyAuthority(vararg authorities: String): String {
+        val anyAuthorities = authorities.joinToString("','")
+        return "hasAnyAuthority('$anyAuthorities')"
+    }
+
     /**
      * Specify that URLs require a particular role.
      *
@@ -162,6 +174,18 @@ class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() {
      */
     fun hasRole(role: String) = "hasRole('$role')"
 
+    /**
+     * Specify that URLs requires any of a number roles.
+     *
+     * @param roles the roles to require (i.e. USER, ADMIN, etc).
+     * @return the SpEL expression "hasAnyRole" with the given roles as a
+     * parameter
+     */
+    fun hasAnyRole(vararg roles: String): String {
+        val anyRoles = roles.joinToString("','")
+        return "hasAnyRole('$anyRoles')"
+    }
+
     /**
      * Specify that URLs are allowed by anyone.
      */

+ 136 - 0
config/src/test/kotlin/org/springframework/security/config/web/servlet/AuthorizeRequestsDslTests.kt

@@ -267,6 +267,142 @@ class AuthorizeRequestsDslTests {
         }
     }
 
+    @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 : WebSecurityConfigurerAdapter() {
+        override fun configure(http: HttpSecurity) {
+            http {
+                authorizeRequests {
+                    authorize("/**", hasAnyRole("ADMIN", "USER"))
+                }
+                httpBasic { }
+            }
+        }
+
+        @RestController
+        internal class PathController {
+            @GetMapping("/")
+            fun index() {
+            }
+        }
+
+        @Bean
+        override 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 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 : WebSecurityConfigurerAdapter() {
+        override fun configure(http: HttpSecurity) {
+            http {
+                authorizeRequests {
+                    authorize("/**", hasAnyAuthority("ROLE_ADMIN", "ROLE_USER"))
+                }
+                httpBasic { }
+            }
+        }
+
+        @RestController
+        internal class PathController {
+            @GetMapping("/")
+            fun index() {
+            }
+        }
+
+        @Bean
+        override 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()