Skip to content

Commit e60ae49

Browse files
rmartinusrwinch
authored andcommitted
Add hasAnyAuthority() and hasAnyRole() in AuthorizeExchangeSpec
Fixes gh-6306
1 parent a919b4e commit e60ae49

File tree

3 files changed

+114
-7
lines changed

3 files changed

+114
-7
lines changed

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

+18
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,15 @@ public AuthorizeExchangeSpec hasRole(String role) {
15631563
return access(AuthorityReactiveAuthorizationManager.hasRole(role));
15641564
}
15651565

1566+
/**
1567+
* Require any specific role. This is a shortcut for {@link #hasAnyAuthority(String...)}
1568+
* @param roles the roles (i.e. "USER" would require "ROLE_USER")
1569+
* @return the {@link AuthorizeExchangeSpec} to configure
1570+
*/
1571+
public AuthorizeExchangeSpec hasAnyRole(String... roles) {
1572+
return access(AuthorityReactiveAuthorizationManager.hasAnyRole(roles));
1573+
}
1574+
15661575
/**
15671576
* Require a specific authority.
15681577
* @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
@@ -1572,6 +1581,15 @@ public AuthorizeExchangeSpec hasAuthority(String authority) {
15721581
return access(AuthorityReactiveAuthorizationManager.hasAuthority(authority));
15731582
}
15741583

1584+
/**
1585+
* Require any authority
1586+
* @param authorities the authorities to require (i.e. "USER" would require authority of "USER").
1587+
* @return the {@link AuthorizeExchangeSpec} to configure
1588+
*/
1589+
public AuthorizeExchangeSpec hasAnyAuthority(String... authorities) {
1590+
return access(AuthorityReactiveAuthorizationManager.hasAnyAuthority(authorities));
1591+
}
1592+
15751593
/**
15761594
* Require an authenticated user
15771595
* @return the {@link AuthorizeExchangeSpec} to configure

core/src/main/java/org/springframework/security/authorization/AuthorityReactiveAuthorizationManager.java

+49-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,10 @@
2020
import org.springframework.util.Assert;
2121
import reactor.core.publisher.Mono;
2222

23+
import java.util.Arrays;
24+
import java.util.List;
25+
import java.util.stream.Stream;
26+
2327
/**
2428
* A {@link ReactiveAuthorizationManager} that determines if the current user is
2529
* authorized by evaluating if the {@link Authentication} contains a specified authority.
@@ -29,19 +33,19 @@
2933
* @param <T> the type of object being authorized
3034
*/
3135
public class AuthorityReactiveAuthorizationManager<T> implements ReactiveAuthorizationManager<T> {
32-
private final String authority;
36+
private final List<String> authorities;
3337

34-
private AuthorityReactiveAuthorizationManager(String authority) {
35-
this.authority = authority;
38+
private AuthorityReactiveAuthorizationManager(String... authorities) {
39+
this.authorities = Arrays.asList(authorities);
3640
}
3741

3842
@Override
3943
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
4044
return authentication
4145
.filter(a -> a.isAuthenticated())
4246
.flatMapIterable( a -> a.getAuthorities())
43-
.map( g-> g.getAuthority())
44-
.hasElement(this.authority)
47+
.map(g -> g.getAuthority())
48+
.any(a -> this.authorities.contains(a))
4549
.map( hasAuthority -> new AuthorizationDecision(hasAuthority))
4650
.defaultIfEmpty(new AuthorizationDecision(false));
4751
}
@@ -59,6 +63,24 @@ public static <T> AuthorityReactiveAuthorizationManager<T> hasAuthority(String a
5963
return new AuthorityReactiveAuthorizationManager<>(authority);
6064
}
6165

66+
/**
67+
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
68+
* provided authorities.
69+
*
70+
* @author Robbie Martinus
71+
* @param authorities the authorities to check for
72+
* @param <T> the type of object being authorized
73+
* @return the new instance
74+
*/
75+
public static <T> AuthorityReactiveAuthorizationManager<T> hasAnyAuthority(String... authorities) {
76+
Assert.notNull(authorities, "authorities cannot be null");
77+
for (String authority : authorities) {
78+
Assert.notNull(authority, "authority cannot be null");
79+
}
80+
81+
return new AuthorityReactiveAuthorizationManager<>(authorities);
82+
}
83+
6284
/**
6385
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
6486
* provided authority.
@@ -71,4 +93,25 @@ public static <T> AuthorityReactiveAuthorizationManager<T> hasRole(String role)
7193
Assert.notNull(role, "role cannot be null");
7294
return hasAuthority("ROLE_" + role);
7395
}
96+
97+
/**
98+
* Creates an instance of {@link AuthorityReactiveAuthorizationManager} with the
99+
* provided authorities.
100+
*
101+
* @author Robbie Martinus
102+
* @param roles the authorities to check for prefixed with "ROLE_"
103+
* @param <T> the type of object being authorized
104+
* @return the new instance
105+
*/
106+
public static <T> AuthorityReactiveAuthorizationManager<T> hasAnyRole(String... roles) {
107+
Assert.notNull(roles, "roles cannot be null");
108+
for (String role : roles) {
109+
Assert.notNull(role, "role cannot be null");
110+
}
111+
112+
return hasAnyAuthority(Stream.of(roles)
113+
.map(r -> "ROLE_" + r)
114+
.toArray(String[]::new)
115+
);
116+
}
74117
}

core/src/test/java/org/springframework/security/authorization/AuthorityReactiveAuthorizationManagerTests.java

+47-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public void checkWhenHasRoleAndAuthorizedThenReturnTrue() {
105105
}
106106

107107
@Test
108-
public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() {
108+
public void checkWhenHasRoleAndNotAuthorizedThenReturnFalse() {
109109
manager = AuthorityReactiveAuthorizationManager.hasRole("ADMIN");
110110
authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN");
111111

@@ -114,6 +114,26 @@ public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() {
114114
assertThat(granted).isFalse();
115115
}
116116

117+
@Test
118+
public void checkWhenHasAnyRoleAndAuthorizedThenReturnTrue() {
119+
manager = AuthorityReactiveAuthorizationManager.hasAnyRole("GENERAL", "USER", "TEST");
120+
authentication = new TestingAuthenticationToken("rob", "secret", "ROLE_USER", "ROLE_AUDITING", "ROLE_ADMIN");
121+
122+
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
123+
124+
assertThat(granted).isTrue();
125+
}
126+
127+
@Test
128+
public void checkWhenHasAnyRoleAndNotAuthorizedThenReturnFalse() {
129+
manager = AuthorityReactiveAuthorizationManager.hasAnyRole("GENERAL", "USER", "TEST");
130+
authentication = new TestingAuthenticationToken("rob", "secret", "USER", "AUDITING", "ADMIN");
131+
132+
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
133+
134+
assertThat(granted).isFalse();
135+
}
136+
117137
@Test(expected = IllegalArgumentException.class)
118138
public void hasRoleWhenNullThenException() {
119139
String role = null;
@@ -125,4 +145,30 @@ public void hasAuthorityWhenNullThenException() {
125145
String authority = null;
126146
AuthorityReactiveAuthorizationManager.hasAuthority(authority);
127147
}
148+
149+
@Test(expected = IllegalArgumentException.class)
150+
public void hasAnyRoleWhenNullThenException() {
151+
String role = null;
152+
AuthorityReactiveAuthorizationManager.hasAnyRole(role);
153+
}
154+
155+
@Test(expected = IllegalArgumentException.class)
156+
public void hasAnyAuthorityWhenNullThenException() {
157+
String authority = null;
158+
AuthorityReactiveAuthorizationManager.hasAnyAuthority(authority);
159+
}
160+
161+
@Test(expected = IllegalArgumentException.class)
162+
public void hasAnyRoleWhenOneIsNullThenException() {
163+
String role1 = "ROLE_ADMIN";
164+
String role2 = null;
165+
AuthorityReactiveAuthorizationManager.hasAnyRole(role1, role2);
166+
}
167+
168+
@Test(expected = IllegalArgumentException.class)
169+
public void hasAnyAuthorityWhenOneIsNullThenException() {
170+
String authority1 = "ADMIN";
171+
String authority2 = null;
172+
AuthorityReactiveAuthorizationManager.hasAnyAuthority(authority1, authority2);
173+
}
128174
}

0 commit comments

Comments
 (0)