From d557d2d0ebf7df9733bef82fa87762f5bd6aa454 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Wed, 1 Jun 2022 01:28:28 +0300 Subject: [PATCH] Add RoleHierarchy to AuthorityAuthorizationManager Added roleHierarchy field to AuthorityAuthorizationManager that defaults to NullRoleHierarchy along with setter method to override. Closes gh-11304 --- .../AuthorityAuthorizationManager.java | 22 ++++++++++- .../AuthorityAuthorizationManagerTests.java | 38 ++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorityAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/AuthorityAuthorizationManager.java index 43af8a5cb8..4a180cf1aa 100644 --- a/core/src/main/java/org/springframework/security/authorization/AuthorityAuthorizationManager.java +++ b/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 implements AuthorizationMana private final List 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 implements AuthorizationMana private boolean isAuthorized(Authentication authentication) { Set 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 implements AuthorizationMana return false; } + private Collection getGrantedAuthorities(Authentication authentication) { + return this.roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities()); + } + @Override public String toString() { return "AuthorityAuthorizationManager[authorities=" + this.authorities + "]"; diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorityAuthorizationManagerTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorityAuthorizationManagerTests.java index ce5d40604b..7054910334 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorityAuthorizationManagerTests.java +++ b/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 manager = AuthorityAuthorizationManager.hasRole("USER"); + assertThatIllegalArgumentException().isThrownBy(() -> manager.setRoleHierarchy(null)) + .withMessage("roleHierarchy cannot be null"); + } + + @Test + public void setRoleHierarchyWhenNotNullThenVerifyRoleHierarchy() { + AuthorityAuthorizationManager manager = AuthorityAuthorizationManager.hasRole("USER"); + RoleHierarchy roleHierarchy = new RoleHierarchyImpl(); + manager.setRoleHierarchy(roleHierarchy); + assertThat(manager).extracting("roleHierarchy").isEqualTo(roleHierarchy); + } + + @Test + public void getRoleHierarchyWhenNotSetThenDefaultsToNullRoleHierarchy() { + AuthorityAuthorizationManager manager = AuthorityAuthorizationManager.hasRole("USER"); + assertThat(manager).extracting("roleHierarchy").isInstanceOf(NullRoleHierarchy.class); + } + + @Test + public void hasRoleWhenRoleHierarchySetThenGreaterRoleTakesPrecedence() { + AuthorityAuthorizationManager manager = AuthorityAuthorizationManager.hasRole("USER"); + RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); + roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER"); + manager.setRoleHierarchy(roleHierarchy); + Supplier authentication = () -> new TestingAuthenticationToken("user", "password", + "ROLE_ADMIN"); + Object object = new Object(); + assertThat(manager.check(authentication, object).isGranted()).isTrue(); + } + }