Просмотр исходного кода

Support RoleHierarchy in AclAuthorizationStrategyImpl

Closes gh-4186
Marcus Hert Da Coregio 1 год назад
Родитель
Сommit
1d3cb3f28e

+ 18 - 1
acl/src/main/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImpl.java

@@ -17,10 +17,13 @@
 package org.springframework.security.acls.domain;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
 import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.acls.model.Acl;
 import org.springframework.security.acls.model.Sid;
 import org.springframework.security.acls.model.SidRetrievalStrategy;
@@ -59,6 +62,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
 
 	private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
 
+	private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
+
 	/**
 	 * Constructor. The only mandatory parameter relates to the system-wide
 	 * {@link GrantedAuthority} instances that can be held to always permit ACL changes.
@@ -100,7 +105,9 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
 		}
 
 		// Iterate this principal's authorities to determine right
-		Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
+		Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
+			.getReachableGrantedAuthorities(authentication.getAuthorities());
+		Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
 		if (acl.getOwner() instanceof GrantedAuthoritySid
 				&& authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
 			return;
@@ -162,4 +169,14 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
 		this.securityContextHolderStrategy = securityContextHolderStrategy;
 	}
 
+	/**
+	 * Sets the {@link RoleHierarchy} to use. The default is to use a
+	 * {@link NullRoleHierarchy}
+	 * @since 6.4
+	 */
+	public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
+		Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
+		this.roleHierarchy = roleHierarchy;
+	}
+
 }

+ 12 - 0
acl/src/test/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImplTests.java

@@ -18,6 +18,7 @@ package org.springframework.security.acls.domain;
 
 import java.util.Arrays;
 
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -25,6 +26,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
+import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
 import org.springframework.security.acls.model.Acl;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
@@ -34,6 +36,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.context.SecurityContextHolderStrategy;
 import org.springframework.security.core.context.SecurityContextImpl;
 
+import static org.assertj.core.api.Assertions.assertThatNoException;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.verify;
 
@@ -86,6 +89,15 @@ public class AclAuthorizationStrategyImplTests {
 		this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL);
 	}
 
+	@Test
+	public void securityCheckWhenRoleReachableByHierarchyThenAuthorized() {
+		given(this.acl.getOwner()).willReturn(new GrantedAuthoritySid("ROLE_AUTH_B"));
+		this.strategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_SYSTEM_ADMIN"));
+		this.strategy.setRoleHierarchy(RoleHierarchyImpl.fromHierarchy("ROLE_AUTH > ROLE_AUTH_B"));
+		assertThatNoException()
+			.isThrownBy(() -> this.strategy.securityCheck(this.acl, AclAuthorizationStrategy.CHANGE_GENERAL));
+	}
+
 	@Test
 	public void securityCheckWhenCustomSecurityContextHolderStrategyThenUses() {
 		given(this.securityContextHolderStrategy.getContext()).willReturn(this.context);

+ 2 - 0
docs/modules/ROOT/pages/whats-new.adoc

@@ -3,3 +3,5 @@
 
 Spring Security 6.4 provides a number of new features.
 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.
+
+- https://github.com/spring-projects/spring-security/issues/4186[gh-4186] - Support `RoleHierarchy` in `AclAuthorizationStrategyImpl`