mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-01 10:59:16 +00:00
Polish OAuth2AuthorizationManagers
- Add OAuth2ReactiveAuthorizationManagers - Code to interfaces - Align error message with the same in AuthorityAuthorizationManager - Adjust expectations in tests to confirm an appropriately constructed authorizaion manager - Add JavaDoc and reference documentation Issue gh-13654
This commit is contained in:
parent
2ee8f27997
commit
a3227f041c
@ -165,11 +165,13 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
http
|
http
|
||||||
.authorizeExchange(exchanges -> exchanges
|
.authorizeExchange(exchanges -> exchanges
|
||||||
.pathMatchers("/message/**").hasAuthority("SCOPE_message:read")
|
.pathMatchers("/message/**").access(hasScope("message:read"))
|
||||||
.anyExchange().authenticated()
|
.anyExchange().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2
|
.oauth2ResourceServer(oauth2 -> oauth2
|
||||||
@ -183,11 +185,13 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||||
return http {
|
return http {
|
||||||
authorizeExchange {
|
authorizeExchange {
|
||||||
authorize("/message/**", hasAuthority("SCOPE_message:read"))
|
authorize("/message/**", hasScope("message:read"))
|
||||||
authorize(anyExchange, authenticated)
|
authorize(anyExchange, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
@ -682,12 +686,14 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
http
|
http
|
||||||
.authorizeExchange(exchanges -> exchanges
|
.authorizeExchange(exchanges -> exchanges
|
||||||
.mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
|
.mvcMatchers("/contacts/**").access(hasScope("contacts"))
|
||||||
.mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
|
.mvcMatchers("/messages/**").access(hasScope("messages"))
|
||||||
.anyExchange().authenticated()
|
.anyExchange().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt);
|
.oauth2ResourceServer(OAuth2ResourceServerSpec::jwt);
|
||||||
@ -699,12 +705,14 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||||
return http {
|
return http {
|
||||||
authorizeExchange {
|
authorizeExchange {
|
||||||
authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
|
authorize("/contacts/**", hasScope("contacts"))
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_messages"))
|
authorize("/messages/**", hasScope("messages"))
|
||||||
authorize(anyExchange, authenticated)
|
authorize(anyExchange, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
|
@ -214,6 +214,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebFluxSecurity
|
@EnableWebFluxSecurity
|
||||||
public class MyCustomSecurityConfiguration {
|
public class MyCustomSecurityConfiguration {
|
||||||
@ -221,7 +223,7 @@ public class MyCustomSecurityConfiguration {
|
|||||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
http
|
http
|
||||||
.authorizeExchange(exchanges -> exchanges
|
.authorizeExchange(exchanges -> exchanges
|
||||||
.pathMatchers("/messages/**").hasAuthority("SCOPE_message:read")
|
.pathMatchers("/messages/**").access(hasScope("message:read"))
|
||||||
.anyExchange().authenticated()
|
.anyExchange().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2
|
.oauth2ResourceServer(oauth2 -> oauth2
|
||||||
@ -238,11 +240,13 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||||
return http {
|
return http {
|
||||||
authorizeExchange {
|
authorizeExchange {
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_message:read"))
|
authorize("/messages/**", hasScope("message:read"))
|
||||||
authorize(anyExchange, authenticated)
|
authorize(anyExchange, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
@ -442,6 +446,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebFluxSecurity
|
@EnableWebFluxSecurity
|
||||||
public class MappedAuthorities {
|
public class MappedAuthorities {
|
||||||
@ -449,8 +455,8 @@ public class MappedAuthorities {
|
|||||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||||
http
|
http
|
||||||
.authorizeExchange(exchange -> exchange
|
.authorizeExchange(exchange -> exchange
|
||||||
.pathMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
|
.pathMatchers("/contacts/**").access(hasScope("contacts"))
|
||||||
.pathMatchers("/messages/**").hasAuthority("SCOPE_messages")
|
.pathMatchers("/messages/**").access(hasScope("messages"))
|
||||||
.anyExchange().authenticated()
|
.anyExchange().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::opaqueToken);
|
.oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::opaqueToken);
|
||||||
@ -463,12 +469,14 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2ReactiveAuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||||
return http {
|
return http {
|
||||||
authorizeExchange {
|
authorizeExchange {
|
||||||
authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
|
authorize("/contacts/**", hasScope("contacts"))
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_messages"))
|
authorize("/messages/**", hasScope("messages"))
|
||||||
authorize(anyExchange, authenticated)
|
authorize(anyExchange, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
|
@ -211,6 +211,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class MyCustomSecurityConfiguration {
|
public class MyCustomSecurityConfiguration {
|
||||||
@ -218,7 +220,7 @@ public class MyCustomSecurityConfiguration {
|
|||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorize -> authorize
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
.requestMatchers("/messages/**").hasAuthority("SCOPE_message:read")
|
.requestMatchers("/messages/**").access(hasScope("message:read"))
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2
|
.oauth2ResourceServer(oauth2 -> oauth2
|
||||||
@ -235,6 +237,8 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
class MyCustomSecurityConfiguration {
|
class MyCustomSecurityConfiguration {
|
||||||
@ -242,7 +246,7 @@ class MyCustomSecurityConfiguration {
|
|||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
authorizeRequests {
|
authorizeRequests {
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_message:read"))
|
authorize("/messages/**", hasScope("message:read"))
|
||||||
authorize(anyRequest, authenticated)
|
authorize(anyRequest, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
@ -862,6 +866,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class DirectlyConfiguredJwkSetUri {
|
public class DirectlyConfiguredJwkSetUri {
|
||||||
@ -869,8 +875,8 @@ public class DirectlyConfiguredJwkSetUri {
|
|||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorize -> authorize
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
.requestMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
|
.requestMatchers("/contacts/**").access(hasScope("contacts"))
|
||||||
.requestMatchers("/messages/**").hasAuthority("SCOPE_messages")
|
.requestMatchers("/messages/**").access(hasScope("messages"))
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||||
@ -883,6 +889,8 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
class DirectlyConfiguredJwkSetUri {
|
class DirectlyConfiguredJwkSetUri {
|
||||||
@ -890,8 +898,8 @@ class DirectlyConfiguredJwkSetUri {
|
|||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
authorizeRequests {
|
authorizeRequests {
|
||||||
authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
|
authorize("/contacts/**", hasScope("contacts"))
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_messages"))
|
authorize("/messages/**", hasScope("messages"))
|
||||||
authorize(anyRequest, authenticated)
|
authorize(anyRequest, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
|
@ -239,6 +239,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class MyCustomSecurityConfiguration {
|
public class MyCustomSecurityConfiguration {
|
||||||
@ -246,7 +248,7 @@ public class MyCustomSecurityConfiguration {
|
|||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorize -> authorize
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
.requestMatchers("/messages/**").hasAuthority("SCOPE_message:read")
|
.requestMatchers("/messages/**").access(hasScope("message:read"))
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2
|
.oauth2ResourceServer(oauth2 -> oauth2
|
||||||
@ -263,6 +265,8 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
class MyCustomSecurityConfiguration {
|
class MyCustomSecurityConfiguration {
|
||||||
@ -270,7 +274,7 @@ class MyCustomSecurityConfiguration {
|
|||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
authorizeRequests {
|
authorizeRequests {
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_message:read"))
|
authorize("/messages/**", hasScope("SCOPE_message:read"))
|
||||||
authorize(anyRequest, authenticated)
|
authorize(anyRequest, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
@ -547,6 +551,8 @@ Java::
|
|||||||
+
|
+
|
||||||
[source,java,role="primary"]
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
import static org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class MappedAuthorities {
|
public class MappedAuthorities {
|
||||||
@ -554,8 +560,8 @@ public class MappedAuthorities {
|
|||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
|
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
|
||||||
.requestMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
|
.requestMatchers("/contacts/**").access(hasScope("contacts"))
|
||||||
.requestMatchers("/messages/**").hasAuthority("SCOPE_messages")
|
.requestMatchers("/messages/**").access(hasScope("messages"))
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
|
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken);
|
||||||
@ -568,6 +574,8 @@ Kotlin::
|
|||||||
+
|
+
|
||||||
[source,kotlin,role="secondary"]
|
[source,kotlin,role="secondary"]
|
||||||
----
|
----
|
||||||
|
import org.springframework.security.oauth2.core.authorization.OAuth2AuthorizationManagers.hasScope
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
class MappedAuthorities {
|
class MappedAuthorities {
|
||||||
@ -575,8 +583,8 @@ class MappedAuthorities {
|
|||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
authorizeRequests {
|
authorizeRequests {
|
||||||
authorize("/contacts/**", hasAuthority("SCOPE_contacts"))
|
authorize("/contacts/**", hasScope("contacts"))
|
||||||
authorize("/messages/**", hasAuthority("SCOPE_messages"))
|
authorize("/messages/**", hasScope("messages"))
|
||||||
authorize(anyRequest, authenticated)
|
authorize(anyRequest, authenticated)
|
||||||
}
|
}
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2023 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.oauth2.core;
|
|
||||||
|
|
||||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Mario Petrovski
|
|
||||||
* @since 6.2
|
|
||||||
*/
|
|
||||||
public final class OAuth2AuthorizationManagers {
|
|
||||||
|
|
||||||
private OAuth2AuthorizationManagers() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> AuthorityAuthorizationManager<T> hasScope(String scope) {
|
|
||||||
verifyScope(scope);
|
|
||||||
return AuthorityAuthorizationManager.hasAuthority("SCOPE_" + scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> AuthorityAuthorizationManager<T> hasAnyScope(String... scopes) {
|
|
||||||
verifyScopes(scopes);
|
|
||||||
String[] mappedScopes = new String[scopes.length];
|
|
||||||
for (int i = 0; i < scopes.length; i++) {
|
|
||||||
mappedScopes[i] = "SCOPE_" + scopes[i];
|
|
||||||
}
|
|
||||||
return AuthorityAuthorizationManager.hasAnyAuthority(mappedScopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void verifyScopes(String... scopes) throws IllegalArgumentException {
|
|
||||||
for (String scope : scopes) {
|
|
||||||
verifyScope(scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void verifyScope(String scope) {
|
|
||||||
if (scope.startsWith("SCOPE_")) {
|
|
||||||
throw new IllegalArgumentException("Scope '" + scope + "' start with 'SCOPE_' prefix.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2023 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.oauth2.core.authorization;
|
||||||
|
|
||||||
|
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience class for creating OAuth 2.0-specific {@link AuthorizationManager}s.
|
||||||
|
*
|
||||||
|
* @author Mario Petrovski
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.2
|
||||||
|
* @see AuthorityAuthorizationManager
|
||||||
|
*/
|
||||||
|
public final class OAuth2AuthorizationManagers {
|
||||||
|
|
||||||
|
private OAuth2AuthorizationManagers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an {@link AuthorizationManager} that requires an {@link Authentication} to
|
||||||
|
* have a {@code SCOPE_scope} authority.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, if you call {@code hasScope("read")}, then this will require that each
|
||||||
|
* authentication have a {@link org.springframework.security.core.GrantedAuthority}
|
||||||
|
* whose value is {@code SCOPE_read}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This would equivalent to calling
|
||||||
|
* {@code AuthorityAuthorizationManager#hasAuthority("SCOPE_read")}.
|
||||||
|
* @param scope the scope value to require
|
||||||
|
* @param <T> the secure object
|
||||||
|
* @return an {@link AuthorizationManager} that requires a {@code "SCOPE_scope"}
|
||||||
|
* authority
|
||||||
|
*/
|
||||||
|
public static <T> AuthorizationManager<T> hasScope(String scope) {
|
||||||
|
assertScope(scope);
|
||||||
|
return AuthorityAuthorizationManager.hasAuthority("SCOPE_" + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an {@link AuthorizationManager} that requires an {@link Authentication} to
|
||||||
|
* have at least one authority among {@code SCOPE_scope1}, {@code SCOPE_scope2}, ...
|
||||||
|
* {@code SCOPE_scopeN}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, if you call {@code hasAnyScope("read", "write")}, then this will
|
||||||
|
* require that each authentication have at least a
|
||||||
|
* {@link org.springframework.security.core.GrantedAuthority} whose value is either
|
||||||
|
* {@code SCOPE_read} or {@code SCOPE_write}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This would equivalent to calling
|
||||||
|
* {@code AuthorityAuthorizationManager#hasAnyAuthority("SCOPE_read", "SCOPE_write")}.
|
||||||
|
* @param scopes the scope values to allow
|
||||||
|
* @param <T> the secure object
|
||||||
|
* @return an {@link AuthorizationManager} that requires at least one authority among
|
||||||
|
* {@code "SCOPE_scope1"}, {@code SCOPE_scope2}, ... {@code SCOPE_scopeN}.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static <T> AuthorizationManager<T> hasAnyScope(String... scopes) {
|
||||||
|
String[] mappedScopes = new String[scopes.length];
|
||||||
|
for (int i = 0; i < scopes.length; i++) {
|
||||||
|
assertScope(scopes[i]);
|
||||||
|
mappedScopes[i] = "SCOPE_" + scopes[i];
|
||||||
|
}
|
||||||
|
return AuthorityAuthorizationManager.hasAnyAuthority(mappedScopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertScope(String scope) {
|
||||||
|
Assert.isTrue(!scope.startsWith("SCOPE_"),
|
||||||
|
() -> scope + " should not start with SCOPE_ since SCOPE_"
|
||||||
|
+ " is automatically prepended when using hasScope and hasAnyScope. Consider using "
|
||||||
|
+ " AuthorityAuthorizationManager#hasAuthority or #hasAnyAuthority instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2023 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.oauth2.core.authorization;
|
||||||
|
|
||||||
|
import org.springframework.security.authorization.AuthorityReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience class for creating OAuth 2.0-specific {@link AuthorizationManager}s.
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.2
|
||||||
|
* @see AuthorityReactiveAuthorizationManager
|
||||||
|
*/
|
||||||
|
public final class OAuth2ReactiveAuthorizationManagers {
|
||||||
|
|
||||||
|
private OAuth2ReactiveAuthorizationManagers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link ReactiveAuthorizationManager} that requires an
|
||||||
|
* {@link Authentication} to have a {@code SCOPE_scope} authority.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, if you call {@code hasScope("read")}, then this will require that each
|
||||||
|
* authentication have a {@link org.springframework.security.core.GrantedAuthority}
|
||||||
|
* whose value is {@code SCOPE_read}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This would equivalent to calling
|
||||||
|
* {@code AuthorityReactiveAuthorizationManager#hasAuthority("SCOPE_read")}.
|
||||||
|
* @param scope the scope value to require
|
||||||
|
* @param <T> the secure object
|
||||||
|
* @return an {@link ReactiveAuthorizationManager} that requires a
|
||||||
|
* {@code "SCOPE_scope"} authority
|
||||||
|
*/
|
||||||
|
public static <T> ReactiveAuthorizationManager<T> hasScope(String scope) {
|
||||||
|
assertScope(scope);
|
||||||
|
return AuthorityReactiveAuthorizationManager.hasAuthority("SCOPE_" + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link ReactiveAuthorizationManager} that requires an
|
||||||
|
* {@link Authentication} to have at least one authority among {@code SCOPE_scope1},
|
||||||
|
* {@code SCOPE_scope2}, ... {@code SCOPE_scopeN}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, if you call {@code hasAnyScope("read", "write")}, then this will
|
||||||
|
* require that each authentication have at least a
|
||||||
|
* {@link org.springframework.security.core.GrantedAuthority} whose value is either
|
||||||
|
* {@code SCOPE_read} or {@code SCOPE_write}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This would equivalent to calling
|
||||||
|
* {@code AuthorityReactiveAuthorizationManager#hasAnyAuthority("SCOPE_read", "SCOPE_write")}.
|
||||||
|
* @param scopes the scope values to allow
|
||||||
|
* @param <T> the secure object
|
||||||
|
* @return an {@link ReactiveAuthorizationManager} that requires at least one
|
||||||
|
* authority among {@code "SCOPE_scope1"}, {@code SCOPE_scope2}, ...
|
||||||
|
* {@code SCOPE_scopeN}.
|
||||||
|
*/
|
||||||
|
public static <T> ReactiveAuthorizationManager<T> hasAnyScope(String... scopes) {
|
||||||
|
String[] mappedScopes = new String[scopes.length];
|
||||||
|
for (int i = 0; i < scopes.length; i++) {
|
||||||
|
assertScope(scopes[i]);
|
||||||
|
mappedScopes[i] = "SCOPE_" + scopes[i];
|
||||||
|
}
|
||||||
|
return AuthorityReactiveAuthorizationManager.hasAnyAuthority(mappedScopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertScope(String scope) {
|
||||||
|
Assert.isTrue(!scope.startsWith("SCOPE_"),
|
||||||
|
() -> scope + " should not start with SCOPE_ since SCOPE_"
|
||||||
|
+ " is automatically prepended when using hasScope and hasAnyScope. Consider using "
|
||||||
|
+ " AuthorityReactiveAuthorizationManager#hasAuthority or #hasAnyAuthority instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2023 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.oauth2.core;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link OAuth2AuthorizationManagers}
|
|
||||||
*
|
|
||||||
* @author Mario Petrovski
|
|
||||||
*/
|
|
||||||
public class OAuth2AuthorizationManagersTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hasScope_withInvalidScope_shouldThrowIllegalArgumentException() {
|
|
||||||
String scope = "SCOPE_invalid";
|
|
||||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
|
||||||
.isThrownBy(() -> OAuth2AuthorizationManagers.hasScope(scope))
|
|
||||||
.withMessage("Scope 'SCOPE_invalid' start with 'SCOPE_' prefix.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hasScopes_withInvalidScope_shouldThrowIllegalArgumentException() {
|
|
||||||
String[] scopes = { "read", "write", "SCOPE_invalid" };
|
|
||||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
|
||||||
.isThrownBy(() -> OAuth2AuthorizationManagers.hasAnyScope(scopes))
|
|
||||||
.withMessage("Scope 'SCOPE_invalid' start with 'SCOPE_' prefix.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hasScope_withValidScope_shouldPass() {
|
|
||||||
String scope = "read";
|
|
||||||
AuthorityAuthorizationManager<Object> authorizationManager = OAuth2AuthorizationManagers.hasScope(scope);
|
|
||||||
assertThat(authorizationManager).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void hasScope_withValidScopes_shouldPass() {
|
|
||||||
String[] scopes = { "read", "write" };
|
|
||||||
AuthorityAuthorizationManager<Object> authorizationManager = OAuth2AuthorizationManagers.hasAnyScope(scopes);
|
|
||||||
assertThat(authorizationManager).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2023 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.oauth2.core.authorization;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link OAuth2AuthorizationManagers}
|
||||||
|
*
|
||||||
|
* @author Mario Petrovski
|
||||||
|
* @author Josh Cummings
|
||||||
|
*/
|
||||||
|
public class OAuth2AuthorizationManagersTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasScopeWhenInvalidScopeThenThrowIllegalArgument() {
|
||||||
|
String scope = "SCOPE_invalid";
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||||
|
.isThrownBy(() -> OAuth2AuthorizationManagers.hasScope(scope))
|
||||||
|
.withMessageContaining("SCOPE_invalid should not start with SCOPE_");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasAnyScopeWhenInvalidScopeThenThrowIllegalArgument() {
|
||||||
|
String[] scopes = { "read", "write", "SCOPE_invalid" };
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||||
|
.isThrownBy(() -> OAuth2AuthorizationManagers.hasAnyScope(scopes))
|
||||||
|
.withMessageContaining("SCOPE_invalid should not start with SCOPE_");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasScopeWhenValidScopeThenAuthorizationManager() {
|
||||||
|
String scope = "read";
|
||||||
|
AuthorizationManager<Object> authorizationManager = OAuth2AuthorizationManagers.hasScope(scope);
|
||||||
|
authorizationManager.verify(() -> hasScope(scope), new Object());
|
||||||
|
assertThatExceptionOfType(AccessDeniedException.class)
|
||||||
|
.isThrownBy(() -> authorizationManager.verify(() -> hasScope("wrong"), new Object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasAnyScopeWhenValidScopesThenAuthorizationManager() {
|
||||||
|
String[] scopes = { "read", "write" };
|
||||||
|
AuthorizationManager<Object> authorizationManager = OAuth2AuthorizationManagers.hasAnyScope(scopes);
|
||||||
|
for (String scope : scopes) {
|
||||||
|
authorizationManager.verify(() -> hasScope(scope), new Object());
|
||||||
|
}
|
||||||
|
assertThatExceptionOfType(AccessDeniedException.class)
|
||||||
|
.isThrownBy(() -> authorizationManager.verify(() -> hasScope("wrong"), new Object()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication hasScope(String scope) {
|
||||||
|
return new TestingAuthenticationToken("user", "pass", "SCOPE_" + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2023 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.oauth2.core.authorization;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link OAuth2ReactiveAuthorizationManagers}
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
*/
|
||||||
|
public class OAuth2ReactiveAuthorizationManagersTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasScopeWhenInvalidScopeThenThrowIllegalArgument() {
|
||||||
|
String scope = "SCOPE_invalid";
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||||
|
.isThrownBy(() -> OAuth2ReactiveAuthorizationManagers.hasScope(scope))
|
||||||
|
.withMessageContaining("SCOPE_invalid should not start with SCOPE_");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasAnyScopeWhenInvalidScopeThenThrowIllegalArgument() {
|
||||||
|
String[] scopes = { "read", "write", "SCOPE_invalid" };
|
||||||
|
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||||
|
.isThrownBy(() -> OAuth2ReactiveAuthorizationManagers.hasAnyScope(scopes))
|
||||||
|
.withMessageContaining("SCOPE_invalid should not start with SCOPE_");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasScopeWhenValidScopeThenAuthorizationManager() {
|
||||||
|
String scope = "read";
|
||||||
|
ReactiveAuthorizationManager<Object> authorizationManager = OAuth2ReactiveAuthorizationManagers.hasScope(scope);
|
||||||
|
authorizationManager.verify(hasScope(scope), new Object()).block();
|
||||||
|
assertThatExceptionOfType(AccessDeniedException.class)
|
||||||
|
.isThrownBy(() -> authorizationManager.verify(hasScope("wrong"), new Object()).block());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasAnyScopeWhenValidScopesThenAuthorizationManager() {
|
||||||
|
String[] scopes = { "read", "write" };
|
||||||
|
ReactiveAuthorizationManager<Object> authorizationManager = OAuth2ReactiveAuthorizationManagers
|
||||||
|
.hasAnyScope(scopes);
|
||||||
|
for (String scope : scopes) {
|
||||||
|
authorizationManager.verify(hasScope(scope), new Object()).block();
|
||||||
|
}
|
||||||
|
assertThatExceptionOfType(AccessDeniedException.class)
|
||||||
|
.isThrownBy(() -> authorizationManager.verify(hasScope("wrong"), new Object()).block());
|
||||||
|
}
|
||||||
|
|
||||||
|
Mono<Authentication> hasScope(String scope) {
|
||||||
|
return Mono.just(new TestingAuthenticationToken("user", "pass", "SCOPE_" + scope));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user