From 60372a505d045da46c0cab76daafcb7c749a918b Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel CAPEL Date: Fri, 16 Feb 2024 16:58:52 +0100 Subject: [PATCH] [Security] Add retrieval of encompassing role names The aim of this method is to provide a handy way of getting the roles that encompass (or are parent of) an array of roles. It is similar to the getReachableRoleNames from the same interface but instead of retrieving the children roles it retrieves the parent roles. A typical use case would be when we get a user role from a database and need to get all the roles that also have access to what this role can access. --- .../Component/Security/Core/CHANGELOG.md | 5 +++++ .../Security/Core/Role/RoleHierarchy.php | 16 ++++++++++++++++ .../Core/Role/RoleHierarchyInterface.php | 2 ++ .../Core/Tests/Role/RoleHierarchyTest.php | 17 +++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/Symfony/Component/Security/Core/CHANGELOG.md b/src/Symfony/Component/Security/Core/CHANGELOG.md index 47b4a21082738..2b00735b74756 100644 --- a/src/Symfony/Component/Security/Core/CHANGELOG.md +++ b/src/Symfony/Component/Security/Core/CHANGELOG.md @@ -2,6 +2,11 @@ CHANGELOG ========= +7.1 +--- + +* Add `getEncompassingRoleNames` method to `RoleHierarchyInterface` + 7.0 --- diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php index 15c5750d88c62..5de5f3bfcd447 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php @@ -50,6 +50,22 @@ public function getReachableRoleNames(array $roles): array return array_values(array_unique($reachableRoles)); } + public function getEncompassingRoleNames(array $roles): array + { + $encompassingRoles = $roles; + + foreach ($roles as $role) { + foreach ($this->map as $parent => $children) { + if (in_array($role, $children)) { + $encompassingRoles[] = $parent; + } + + } + } + + return array_values(array_unique($encompassingRoles)); + } + protected function buildRoleMap(): void { $this->map = []; diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php index 6e8fa81d07f40..d0b967cdf7024 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php @@ -14,6 +14,8 @@ /** * RoleHierarchyInterface is the interface for a role hierarchy. * + * @method array getEncompassingRoleNames(array $roles) + * * @author Fabien Potencier */ interface RoleHierarchyInterface diff --git a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php index 5c42e0b39f8bf..52f5b97897570 100644 --- a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php @@ -30,4 +30,21 @@ public function testGetReachableRoleNames() $this->assertEquals(['ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_FOO', 'ROLE_USER'], $role->getReachableRoleNames(['ROLE_SUPER_ADMIN'])); $this->assertEquals(['ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_FOO', 'ROLE_USER'], $role->getReachableRoleNames(['ROLE_SUPER_ADMIN', 'ROLE_SUPER_ADMIN'])); } + + public function testGetEncompassingRoleNames() + { + $role = new RoleHierarchy([ + 'ROLE_ADMIN' => ['ROLE_USER'], + 'ROLE_SUPER_ADMIN' => ['ROLE_ADMIN', 'ROLE_FOO'], + 'ROLE_USER' => ['ROLE_BAR'], + ]); + + $this->assertEquals(['ROLE_SUPER_ADMIN'], $role->getEncompassingRoleNames(['ROLE_SUPER_ADMIN'])); + $this->assertEquals(['ROLE_ADMIN', 'ROLE_SUPER_ADMIN'], $role->getEncompassingRoleNames(['ROLE_ADMIN'])); + $this->assertEquals(['ROLE_USER', 'ROLE_ADMIN', 'ROLE_SUPER_ADMIN'], $role->getEncompassingRoleNames(['ROLE_USER'])); + $this->assertEquals(['ROLE_BAR', 'ROLE_ADMIN', 'ROLE_SUPER_ADMIN', 'ROLE_USER'], $role->getEncompassingRoleNames(['ROLE_BAR'])); + $this->assertEquals(['ROLE_SUPER_ADMIN'], $role->getEncompassingRoleNames(['ROLE_SUPER_ADMIN', 'ROLE_SUPER_ADMIN'])); + $this->assertEquals(['ROLE_SUPER_ADMIN', 'ROLE_USER', 'ROLE_ADMIN'], $role->getEncompassingRoleNames(['ROLE_SUPER_ADMIN', 'ROLE_USER'])); + $this->assertEquals(['ROLE_BAR', 'ROLE_FOO','ROLE_ADMIN', 'ROLE_SUPER_ADMIN', 'ROLE_USER'], $role->getEncompassingRoleNames(['ROLE_BAR', 'ROLE_FOO'])); + } }