Skip to content

Commit 1d3cb3f

Browse files
Support RoleHierarchy in AclAuthorizationStrategyImpl
Closes gh-4186
1 parent 752a56a commit 1d3cb3f

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

acl/src/main/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImpl.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
package org.springframework.security.acls.domain;
1818

1919
import java.util.Arrays;
20+
import java.util.Collection;
2021
import java.util.List;
2122
import java.util.Set;
2223

2324
import org.springframework.security.access.AccessDeniedException;
25+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
26+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
2427
import org.springframework.security.acls.model.Acl;
2528
import org.springframework.security.acls.model.Sid;
2629
import org.springframework.security.acls.model.SidRetrievalStrategy;
@@ -59,6 +62,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
5962

6063
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
6164

65+
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
66+
6267
/**
6368
* Constructor. The only mandatory parameter relates to the system-wide
6469
* {@link GrantedAuthority} instances that can be held to always permit ACL changes.
@@ -100,7 +105,9 @@ public void securityCheck(Acl acl, int changeType) {
100105
}
101106

102107
// Iterate this principal's authorities to determine right
103-
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
108+
Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
109+
.getReachableGrantedAuthorities(authentication.getAuthorities());
110+
Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
104111
if (acl.getOwner() instanceof GrantedAuthoritySid
105112
&& authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
106113
return;
@@ -162,4 +169,14 @@ public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy secur
162169
this.securityContextHolderStrategy = securityContextHolderStrategy;
163170
}
164171

172+
/**
173+
* Sets the {@link RoleHierarchy} to use. The default is to use a
174+
* {@link NullRoleHierarchy}
175+
* @since 6.4
176+
*/
177+
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
178+
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
179+
this.roleHierarchy = roleHierarchy;
180+
}
181+
165182
}

acl/src/test/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImplTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818

1919
import java.util.Arrays;
2020

21+
import org.assertj.core.api.Assertions;
2122
import org.junit.jupiter.api.AfterEach;
2223
import org.junit.jupiter.api.BeforeEach;
2324
import org.junit.jupiter.api.Test;
2425
import org.junit.jupiter.api.extension.ExtendWith;
2526
import org.mockito.Mock;
2627
import org.mockito.junit.jupiter.MockitoExtension;
2728

29+
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
2830
import org.springframework.security.acls.model.Acl;
2931
import org.springframework.security.authentication.TestingAuthenticationToken;
3032
import org.springframework.security.core.GrantedAuthority;
@@ -34,6 +36,7 @@
3436
import org.springframework.security.core.context.SecurityContextHolderStrategy;
3537
import org.springframework.security.core.context.SecurityContextImpl;
3638

39+
import static org.assertj.core.api.Assertions.assertThatNoException;
3740
import static org.mockito.BDDMockito.given;
3841
import static org.mockito.Mockito.verify;
3942

@@ -86,6 +89,15 @@ public void securityCheckWhenAclOwnedByGrantedAuthority() {
8689
this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL);
8790
}
8891

92+
@Test
93+
public void securityCheckWhenRoleReachableByHierarchyThenAuthorized() {
94+
given(this.acl.getOwner()).willReturn(new GrantedAuthoritySid("ROLE_AUTH_B"));
95+
this.strategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_SYSTEM_ADMIN"));
96+
this.strategy.setRoleHierarchy(RoleHierarchyImpl.fromHierarchy("ROLE_AUTH > ROLE_AUTH_B"));
97+
assertThatNoException()
98+
.isThrownBy(() -> this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL));
99+
}
100+
89101
@Test
90102
public void securityCheckWhenCustomSecurityContextHolderStrategyThenUses() {
91103
given(this.securityContextHolderStrategy.getContext()).willReturn(this.context);

docs/modules/ROOT/pages/whats-new.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33

44
Spring Security 6.4 provides a number of new features.
55
Below are the highlights of the release, or you can view https://github.com/spring-projects/spring-security/releases[the release notes] for a detailed listing of each feature and bug fix.
6+
7+
- https://github.com/spring-projects/spring-security/issues/4186[gh-4186] - Support `RoleHierarchy` in `AclAuthorizationStrategyImpl`

0 commit comments

Comments
 (0)