Skip to content

Commit 3cb39c8

Browse files
committed
Add Authority String AuthorizationManager
Closes gh-12231
1 parent 70a6cf6 commit 3cb39c8

File tree

6 files changed

+206
-33
lines changed

6 files changed

+206
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization;
18+
19+
import java.util.Collection;
20+
import java.util.function.Supplier;
21+
22+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
23+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
24+
import org.springframework.security.core.Authentication;
25+
import org.springframework.security.core.GrantedAuthority;
26+
import org.springframework.security.core.authority.AuthorityUtils;
27+
import org.springframework.util.Assert;
28+
29+
/**
30+
* An {@link AuthorizationManager} that determines if the current user is authorized by
31+
* evaluating if the {@link Authentication} contains any of the specified authorities.
32+
*
33+
* @author Evgeniy Cheban
34+
* @since 6.1
35+
*/
36+
public final class AuthoritiesAuthorizationManager implements AuthorizationManager<Collection<String>> {
37+
38+
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
39+
40+
/**
41+
* Sets the {@link RoleHierarchy} to be used. Default is {@link NullRoleHierarchy}.
42+
* Cannot be null.
43+
* @param roleHierarchy the {@link RoleHierarchy} to use
44+
*/
45+
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
46+
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
47+
this.roleHierarchy = roleHierarchy;
48+
}
49+
50+
/**
51+
* Determines if the current user is authorized by evaluating if the
52+
* {@link Authentication} contains any of specified authorities.
53+
* @param authentication the {@link Supplier} of the {@link Authentication} to check
54+
* @param authorities the collection of authority strings to check
55+
* @return an {@link AuthorityAuthorizationDecision}
56+
*/
57+
@Override
58+
public AuthorityAuthorizationDecision check(Supplier<Authentication> authentication,
59+
Collection<String> authorities) {
60+
boolean granted = isGranted(authentication.get(), authorities);
61+
return new AuthorityAuthorizationDecision(granted, AuthorityUtils.createAuthorityList(authorities));
62+
}
63+
64+
private boolean isGranted(Authentication authentication, Collection<String> authorities) {
65+
return authentication != null && isAuthorized(authentication, authorities);
66+
}
67+
68+
private boolean isAuthorized(Authentication authentication, Collection<String> authorities) {
69+
for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
70+
if (authorities.contains(grantedAuthority.getAuthority())) {
71+
return true;
72+
}
73+
}
74+
return false;
75+
}
76+
77+
private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
78+
return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
79+
}
80+
81+
}

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

+7-29
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@
1616

1717
package org.springframework.security.authorization;
1818

19-
import java.util.Collection;
20-
import java.util.List;
19+
import java.util.Arrays;
20+
import java.util.HashSet;
2121
import java.util.Set;
2222
import java.util.function.Supplier;
2323

2424
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
2525
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
2626
import org.springframework.security.core.Authentication;
27-
import org.springframework.security.core.GrantedAuthority;
28-
import org.springframework.security.core.authority.AuthorityUtils;
2927
import org.springframework.util.Assert;
3028

3129
/**
@@ -40,12 +38,12 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
4038

4139
private static final String ROLE_PREFIX = "ROLE_";
4240

43-
private final List<GrantedAuthority> authorities;
41+
private final AuthoritiesAuthorizationManager delegate = new AuthoritiesAuthorizationManager();
4442

45-
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
43+
private final Set<String> authorities;
4644

4745
private AuthorityAuthorizationManager(String... authorities) {
48-
this.authorities = AuthorityUtils.createAuthorityList(authorities);
46+
this.authorities = new HashSet<>(Arrays.asList(authorities));
4947
}
5048

5149
/**
@@ -55,8 +53,7 @@ private AuthorityAuthorizationManager(String... authorities) {
5553
* @since 5.8
5654
*/
5755
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
58-
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
59-
this.roleHierarchy = roleHierarchy;
56+
this.delegate.setRoleHierarchy(roleHierarchy);
6057
}
6158

6259
/**
@@ -139,26 +136,7 @@ private static String[] toNamedRolesArray(String rolePrefix, String[] roles) {
139136
*/
140137
@Override
141138
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
142-
boolean granted = isGranted(authentication.get());
143-
return new AuthorityAuthorizationDecision(granted, this.authorities);
144-
}
145-
146-
private boolean isGranted(Authentication authentication) {
147-
return authentication != null && authentication.isAuthenticated() && isAuthorized(authentication);
148-
}
149-
150-
private boolean isAuthorized(Authentication authentication) {
151-
Set<String> authorities = AuthorityUtils.authorityListToSet(this.authorities);
152-
for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
153-
if (authorities.contains(grantedAuthority.getAuthority())) {
154-
return true;
155-
}
156-
}
157-
return false;
158-
}
159-
160-
private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
161-
return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
139+
return this.delegate.check(authentication, this.authorities);
162140
}
163141

164142
@Override

core/src/main/java/org/springframework/security/core/authority/AuthorityUtils.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -33,6 +33,7 @@
3333
* Mainly intended for internal use.
3434
*
3535
* @author Luke Taylor
36+
* @author Evgeniy Cheban
3637
*/
3738
public final class AuthorityUtils {
3839

@@ -78,4 +79,18 @@ public static List<GrantedAuthority> createAuthorityList(String... authorities)
7879
return grantedAuthorities;
7980
}
8081

82+
/**
83+
* Converts authorities into a List of GrantedAuthority objects.
84+
* @param authorities the authorities to convert
85+
* @return a List of GrantedAuthority objects
86+
* @since 6.1
87+
*/
88+
public static List<GrantedAuthority> createAuthorityList(Collection<String> authorities) {
89+
List<GrantedAuthority> grantedAuthorities = new ArrayList<>(authorities.size());
90+
for (String authority : authorities) {
91+
grantedAuthorities.add(new SimpleGrantedAuthority(authority));
92+
}
93+
return grantedAuthorities;
94+
}
95+
8196
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization;
18+
19+
import java.util.Arrays;
20+
import java.util.Collections;
21+
import java.util.function.Supplier;
22+
23+
import org.junit.jupiter.api.Test;
24+
25+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
26+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
27+
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
28+
import org.springframework.security.authentication.TestingAuthenticationToken;
29+
import org.springframework.security.core.Authentication;
30+
31+
import static org.assertj.core.api.Assertions.assertThat;
32+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
33+
34+
/**
35+
* Tests for {@link AuthoritiesAuthorizationManager}.
36+
*
37+
* @author Evgeniy Cheban
38+
*/
39+
class AuthoritiesAuthorizationManagerTests {
40+
41+
@Test
42+
void setRoleHierarchyWhenNullThenIllegalArgumentException() {
43+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
44+
assertThatIllegalArgumentException().isThrownBy(() -> manager.setRoleHierarchy(null))
45+
.withMessage("roleHierarchy cannot be null");
46+
}
47+
48+
@Test
49+
void setRoleHierarchyWhenNotNullThenVerifyRoleHierarchy() {
50+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
51+
RoleHierarchy roleHierarchy = new RoleHierarchyImpl();
52+
manager.setRoleHierarchy(roleHierarchy);
53+
assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy);
54+
}
55+
56+
@Test
57+
void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() {
58+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
59+
assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
60+
}
61+
62+
@Test
63+
void checkWhenUserHasAnyAuthorityThenGrantedDecision() {
64+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
65+
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "USER");
66+
assertThat(manager.check(authentication, Arrays.asList("ADMIN", "USER")).isGranted()).isTrue();
67+
}
68+
69+
@Test
70+
void checkWhenUserHasNotAnyAuthorityThenDeniedDecision() {
71+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
72+
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ANONYMOUS");
73+
assertThat(manager.check(authentication, Arrays.asList("ADMIN", "USER")).isGranted()).isFalse();
74+
}
75+
76+
@Test
77+
void hasRoleWhenRoleHierarchySetThenGreaterRoleTakesPrecedence() {
78+
AuthoritiesAuthorizationManager manager = new AuthoritiesAuthorizationManager();
79+
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
80+
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
81+
manager.setRoleHierarchy(roleHierarchy);
82+
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
83+
"ROLE_ADMIN");
84+
assertThat(manager.check(authentication, Collections.singleton("ROLE_ADMIN")).isGranted()).isTrue();
85+
}
86+
87+
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,13 @@ public void setRoleHierarchyWhenNotNullThenVerifyRoleHierarchy() {
226226
AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
227227
RoleHierarchy roleHierarchy = new RoleHierarchyImpl();
228228
manager.setRoleHierarchy(roleHierarchy);
229-
assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy);
229+
assertThat(manager).extracting("delegate").extracting("roleHierarchy").isEqualTo(roleHierarchy);
230230
}
231231

232232
@Test
233233
public void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() {
234234
AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
235-
assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
235+
assertThat(manager).extracting("delegate").extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
236236
}
237237

238238
@Test

core/src/test/java/org/springframework/security/core/authority/AuthorityUtilsTests.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.core.authority;
1818

19+
import java.util.Arrays;
1920
import java.util.List;
2021
import java.util.Set;
2122

@@ -27,6 +28,7 @@
2728

2829
/**
2930
* @author Luke Taylor
31+
* @author Evgeniy Cheban
3032
*/
3133
public class AuthorityUtilsTests {
3234

@@ -42,4 +44,14 @@ public void commaSeparatedStringIsParsedCorrectly() {
4244
assertThat(authorities.contains("ROLE_D")).isTrue();
4345
}
4446

47+
@Test
48+
public void createAuthorityList() {
49+
List<GrantedAuthority> authorities = AuthorityUtils
50+
.createAuthorityList(Arrays.asList("ROLE_A", "ROLE_B", "ROLE_C"));
51+
assertThat(authorities).hasSize(3);
52+
assertThat(authorities).element(0).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_A");
53+
assertThat(authorities).element(1).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_B");
54+
assertThat(authorities).element(2).extracting(GrantedAuthority::getAuthority).isEqualTo("ROLE_C");
55+
}
56+
4557
}

0 commit comments

Comments
 (0)