Pārlūkot izejas kodu

Add RoleHierarchy to AuthorityAuthorizationManager

Added roleHierarchy field to AuthorityAuthorizationManager
that defaults to NullRoleHierarchy along with setter method to override.

Closes gh-11304
Evgeniy Cheban 3 gadi atpakaļ
vecāks
revīzija
5eadcba7d1

+ 21 - 1
core/src/main/java/org/springframework/security/authorization/AuthorityAuthorizationManager.java

@@ -16,10 +16,13 @@
 
 package org.springframework.security.authorization;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Supplier;
 
+import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.AuthorityUtils;
@@ -39,10 +42,23 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 
 	private final List<GrantedAuthority> authorities;
 
+	private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
+
 	private AuthorityAuthorizationManager(String... authorities) {
 		this.authorities = AuthorityUtils.createAuthorityList(authorities);
 	}
 
+	/**
+	 * Sets the {@link RoleHierarchy} to be used. Default is {@link NullRoleHierarchy}.
+	 * Cannot be null.
+	 * @param roleHierarchy the {@link RoleHierarchy} to use
+	 * @since 5.8
+	 */
+	public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
+		Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
+		this.roleHierarchy = roleHierarchy;
+	}
+
 	/**
 	 * Creates an instance of {@link AuthorityAuthorizationManager} with the provided
 	 * authority.
@@ -133,7 +149,7 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 
 	private boolean isAuthorized(Authentication authentication) {
 		Set<String> authorities = AuthorityUtils.authorityListToSet(this.authorities);
-		for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
+		for (GrantedAuthority grantedAuthority : getGrantedAuthorities(authentication)) {
 			if (authorities.contains(grantedAuthority.getAuthority())) {
 				return true;
 			}
@@ -141,6 +157,10 @@ public final class AuthorityAuthorizationManager<T> implements AuthorizationMana
 		return false;
 	}
 
+	private Collection<? extends GrantedAuthority> getGrantedAuthorities(Authentication authentication) {
+		return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
+	}
+
 	@Override
 	public String toString() {
 		return "AuthorityAuthorizationManager[authorities=" + this.authorities + "]";

+ 37 - 1
core/src/test/java/org/springframework/security/authorization/AuthorityAuthorizationManagerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2022 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.
@@ -21,6 +21,9 @@ import java.util.function.Supplier;
 
 import org.junit.jupiter.api.Test;
 
+import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -211,4 +214,37 @@ public class AuthorityAuthorizationManagerTests {
 		assertThat(manager.check(authentication, object).isGranted()).isFalse();
 	}
 
+	@Test
+	public void setRoleHierarchyWhenNullThenIllegalArgumentException() {
+		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
+		assertThatIllegalArgumentException().isThrownBy(() -> manager.setRoleHierarchy(null))
+				.withMessage("roleHierarchy cannot be null");
+	}
+
+	@Test
+	public void setRoleHierarchyWhenNotNullThenVerifyRoleHierarchy() {
+		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
+		RoleHierarchy roleHierarchy = new RoleHierarchyImpl();
+		manager.setRoleHierarchy(roleHierarchy);
+		assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy);
+	}
+
+	@Test
+	public void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() {
+		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
+		assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class);
+	}
+
+	@Test
+	public void hasRoleWhenRoleHierarchySetThenGreaterRoleTakesPrecedence() {
+		AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasRole("USER");
+		RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
+		roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
+		manager.setRoleHierarchy(roleHierarchy);
+		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
+				"ROLE_ADMIN");
+		Object object = new Object();
+		assertThat(manager.check(authentication, object).isGranted()).isTrue();
+	}
+
 }