From 4db173c22a1f5ef4832e55bb69f5819131315c70 Mon Sep 17 00:00:00 2001 From: Bernhard Enders Date: Sat, 9 Nov 2024 14:46:52 -0300 Subject: [PATCH 1/4] Update check wildcard match takes into consideration multilevel permissions. --- src/Authorization/Traits/Authorizable.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Authorization/Traits/Authorizable.php b/src/Authorization/Traits/Authorizable.php index c0b1acf2a..f7132320b 100644 --- a/src/Authorization/Traits/Authorizable.php +++ b/src/Authorization/Traits/Authorizable.php @@ -280,8 +280,13 @@ public function can(string ...$permissions): bool } // Check wildcard match - $check = substr($permission, 0, strpos($permission, '.')) . '.*'; - if (isset($matrix[$group]) && in_array($check, $matrix[$group], true)) { + $checks = []; + $parts = explode('.', $permission); + for ($i = count($parts); $i > 0; $i--) { + $check = implode('.', array_slice($parts, 0, $i)) . '.*'; + $checks[] = $check; + } + if (isset($matrix[$group]) && array_intersect($checks, $matrix[$group])) { return true; } } From 9eeed0cea3d5cf80b2ea106af16ca42260c262dd Mon Sep 17 00:00:00 2001 From: Bernhard Enders Date: Sat, 9 Nov 2024 14:48:17 -0300 Subject: [PATCH 2/4] Update check for wildcard matching takes into consideration multiple permissions levels --- src/Entities/Group.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Entities/Group.php b/src/Entities/Group.php index b63707929..e8a175a3b 100644 --- a/src/Entities/Group.php +++ b/src/Entities/Group.php @@ -85,9 +85,16 @@ public function can(string $permission): bool } // Check wildcard match - $check = substr($permission, 0, strpos($permission, '.')) . '.*'; + $checks = []; + $parts = explode('.', $permission); + for ($i = count($parts); $i > 0; $i--) { + $check = implode('.', array_slice($parts, 0, $i)) . '.*'; + $checks[] = $check; + } - return $this->permissions !== null && $this->permissions !== [] && in_array($check, $this->permissions, true); + return $this->permissions !== null && + $this->permissions !== [] && + array_intersect($checks, $this->permissions); } /** From d7f42f952d81ad404726978e5e28c175ca8743f0 Mon Sep 17 00:00:00 2001 From: Bernhard Enders Date: Sat, 9 Nov 2024 15:07:55 -0300 Subject: [PATCH 3/4] added testCanNestedPerms test test to check multi level permissions properly --- tests/Authorization/GroupTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Authorization/GroupTest.php b/tests/Authorization/GroupTest.php index 68c190be8..bdbc81e0c 100644 --- a/tests/Authorization/GroupTest.php +++ b/tests/Authorization/GroupTest.php @@ -87,4 +87,19 @@ public function testCan(): void $this->assertTrue($group2->can('users.edit')); $this->assertFalse($group2->can('foo.bar')); } + + public function testCanNestedPerms(): void + { + $group = $this->groups->info('user'); + $group->addPermission('foo.bar.*'); + $group->addPermission('foo.biz.buz.*'); + $this->assertTrue($group->can('foo.bar')); + $this->assertTrue($group->can('foo.bar.baz')); + $this->assertTrue($group->can('foo.bar.buz')); + $this->assertTrue($group->can('foo.bar.*')); + $this->assertTrue($group->can('foo.biz.buz')); + $this->assertFalse($group->can('foo.biz.*')); + $this->assertTrue($group->can('foo.biz.buz.bar')); + $this->assertFalse($group->can('foo.biz.bar.buz')); + } } From fe3215f7e58e910228141c37e747bc10701288f4 Mon Sep 17 00:00:00 2001 From: Bernhard Enders Date: Sat, 9 Nov 2024 15:50:30 -0300 Subject: [PATCH 4/4] add support for multi level permissions in can() when using asterisk (*) to give user/group permissions, only one level permissions are supported by can(). This resolves #1224 --- src/Authorization/Traits/Authorizable.php | 10 ++++++++-- src/Entities/Group.php | 12 ++++++++++-- tests/Authorization/GroupTest.php | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Authorization/Traits/Authorizable.php b/src/Authorization/Traits/Authorizable.php index c0b1acf2a..4ed14ac01 100644 --- a/src/Authorization/Traits/Authorizable.php +++ b/src/Authorization/Traits/Authorizable.php @@ -280,8 +280,14 @@ public function can(string ...$permissions): bool } // Check wildcard match - $check = substr($permission, 0, strpos($permission, '.')) . '.*'; - if (isset($matrix[$group]) && in_array($check, $matrix[$group], true)) { + $checks = []; + $parts = explode('.', $permission); + for ($i = count($parts); $i > 0; $i--) { + $check = implode('.', array_slice($parts, 0, $i)) . '.*'; + $checks[] = $check; + } + + if (isset($matrix[$group]) && array_intersect($checks, $matrix[$group])) { return true; } } diff --git a/src/Entities/Group.php b/src/Entities/Group.php index b63707929..41300a22d 100644 --- a/src/Entities/Group.php +++ b/src/Entities/Group.php @@ -85,9 +85,17 @@ public function can(string $permission): bool } // Check wildcard match - $check = substr($permission, 0, strpos($permission, '.')) . '.*'; + $checks = []; + $parts = explode('.', $permission); + for ($i = count($parts); $i > 0; $i--) { + $check = implode('.', array_slice($parts, 0, $i)) . '.*'; + $checks[] = $check; + } + + return $this->permissions !== null && + $this->permissions !== [] && + array_intersect($checks, $this->permissions); - return $this->permissions !== null && $this->permissions !== [] && in_array($check, $this->permissions, true); } /** diff --git a/tests/Authorization/GroupTest.php b/tests/Authorization/GroupTest.php index 68c190be8..cbd6409ae 100644 --- a/tests/Authorization/GroupTest.php +++ b/tests/Authorization/GroupTest.php @@ -87,4 +87,25 @@ public function testCan(): void $this->assertTrue($group2->can('users.edit')); $this->assertFalse($group2->can('foo.bar')); } + + public function testCanNestedPerms(): void + { + $group = $this->groups->info('user'); + + $group->addPermission('foo.bar.*'); + $group->addPermission('foo.biz.buz.*'); + + $this->assertTrue($group->can('foo.bar')); + $this->assertTrue($group->can('foo.bar.*')); + $this->assertTrue($group->can('foo.bar.baz')); + $this->assertTrue($group->can('foo.bar.buz')); + $this->assertFalse($group->can('foo.bar.buz.biz')); + $this->assertTrue($group->can('foo.biz.buz')); + $this->assertTrue($group->can('foo.biz.buz.*')); + $this->assertFalse($group->can('foo.biz')); + $this->assertFalse($group->can('foo.biz.*')); + $this->assertTrue($group->can('foo.biz.buz.bar')); + $this->assertFalse($group->can('foo.biz.bar.buz')); + $this->assertFalse($group->can('foo.biz.buz.bar.boz')); + } }