diff --git a/dev/docs/permission-scenario-testing.md b/dev/docs/permission-scenario-testing.md index 7cd7667d2..b45ffd87f 100644 --- a/dev/docs/permission-scenario-testing.md +++ b/dev/docs/permission-scenario-testing.md @@ -10,28 +10,76 @@ Test cases are written ability abstract, since all abilities should act the same These are tests related to entity-level role-specific permission overrides. -#### entity_role_01 - Explicit allow +#### test_01_explicit_allow - Page permissions have inherit disabled. -- Role A has explicit page permission. +- Role A has entity allow page permission. - User has Role A. User should have page permission. -#### entity_role_02 - Explicit deny +#### test_02_explicit_deny - Page permissions have inherit disabled. -- Role A has explicit page permission. +- Role A has entity deny page permission. - User has Role A. -User should not have permission. +User denied page permission. -#### entity_role_03 - Same level conflicting +#### test_03_same_level_conflicting - Page permissions have inherit disabled. -- Role A has explicit page permission. -- Role B has explicit blocked page permission. +- Role A has entity allow page permission. +- Role B has entity deny page permission. - User has both Role A & B. -User should have page permission. Explicit grant overrides explicit deny at same level. - +User should have page permission. +Explicit grant overrides entity deny at same level. + +#### test_20_inherit_allow + +- Page permissions have inherit enabled. +- Chapter permissions has inherit disabled. +- Role A has entity allow chapter permission. +- User has both Role A. + +User should have page permission. + +#### test_21_inherit_deny + +- Page permissions have inherit enabled. +- Chapter permissions has inherit disabled. +- Role A has entity deny chapter permission. +- User has both Role A. + +User denied page permission. + +#### test_22_same_level_conflict_inherit + +- Page permissions have inherit enabled. +- Chapter permissions has inherit disabled. +- Role A has entity deny chapter permission. +- Role B has entity allow chapter permission. +- User has both Role A & B. + +User should have page permission. + +#### test_30_child_inherit_override_allow + +- Page permissions have inherit enabled. +- Chapter permissions has inherit disabled. +- Role A has entity deny chapter permission. +- Role A has entity allow page permission. +- User has Role A. + +User should have page permission. + +#### test_31_child_inherit_override_deny + +- Page permissions have inherit enabled. +- Chapter permissions has inherit disabled. +- Role A has entity allow chapter permission. +- Role A has entity deny page permission. +- User has Role A. + +User denied page permission. \ No newline at end of file diff --git a/tests/Helpers/PermissionsProvider.php b/tests/Helpers/PermissionsProvider.php index c3cd2ad19..1406cf4cf 100644 --- a/tests/Helpers/PermissionsProvider.php +++ b/tests/Helpers/PermissionsProvider.php @@ -90,9 +90,9 @@ class PermissionsProvider $this->addEntityPermissionEntries($entity, $permissions); } - public function addEntityPermission(Entity $entity, array $actionList, int $roleId = null, int $userId = null) + public function addEntityPermission(Entity $entity, array $actionList, ?Role $role = null, ?User $user = null) { - $permissionData = $this->actionListToEntityPermissionData($actionList, $roleId, $userId); + $permissionData = $this->actionListToEntityPermissionData($actionList, $role->id ?? null, $user->id ?? null); $this->addEntityPermissionEntries($entity, [$permissionData]); } diff --git a/tests/Helpers/UserRoleProvider.php b/tests/Helpers/UserRoleProvider.php index db69a6ac0..a85bd06cf 100644 --- a/tests/Helpers/UserRoleProvider.php +++ b/tests/Helpers/UserRoleProvider.php @@ -59,7 +59,7 @@ class UserRoleProvider public function newUserWithRole(array $userAttrs = [], array $rolePermissions = []): array { $user = User::factory()->create($userAttrs); - $role = $this->attachRole($user, $rolePermissions); + $role = $this->attachNewRole($user, $rolePermissions); return [$user, $role]; } @@ -68,7 +68,7 @@ class UserRoleProvider * Attach a new role, with the given role permissions, to the given user * and return that role. */ - public function attachRole(User $user, array $rolePermissions = []): Role + public function attachNewRole(User $user, array $rolePermissions = []): Role { $role = $this->createRole($rolePermissions); $user->attachRole($role); diff --git a/tests/Permissions/Scenarios/EntityRolePermissions.php b/tests/Permissions/Scenarios/EntityRolePermissions.php index de5bda272..66bb64f22 100644 --- a/tests/Permissions/Scenarios/EntityRolePermissions.php +++ b/tests/Permissions/Scenarios/EntityRolePermissions.php @@ -2,7 +2,8 @@ namespace Tests\Permissions\Scenarios; -use BookStack\Entities\Models\Page; +use BookStack\Auth\User; +use BookStack\Entities\Models\Entity; use Tests\TestCase; // Cases defined in dev/docs/permission-scenario-testing.md @@ -15,34 +16,118 @@ class EntityRolePermissions extends TestCase $page = $this->entities->page(); $this->permissions->setEntityPermissions($page, ['view'], [$role], false); - $this->actingAs($user); - $this->assertTrue(userCan('page-view', $page)); - $this->assertNotNull(Page::visible()->findOrFail($page->id)); + $this->assertVisibleToUser($page, $user); } public function test_02_explicit_deny() { [$user, $role] = $this->users->newUserWithRole(); $page = $this->entities->page(); - $this->permissions->setEntityPermissions($page, ['edit'], [$role], false); + $this->permissions->setEntityPermissions($page, [], [$role], false); - $this->actingAs($user); - $this->assertFalse(userCan('page-view', $page)); - $this->assertNull(Page::visible()->find($page->id)); + $this->assertNotVisibleToUser($page, $user); } public function test_03_same_level_conflicting() { [$user, $roleA] = $this->users->newUserWithRole(); - $roleB = $this->users->attachRole($user); + $roleB = $this->users->attachNewRole($user); $page = $this->entities->page(); $this->permissions->disableEntityInheritedPermissions($page); - $this->permissions->addEntityPermission($page, ['update'], $roleA->id); - $this->permissions->addEntityPermission($page, ['view'], $roleB->id); + $this->permissions->addEntityPermission($page, [], $roleA); + $this->permissions->addEntityPermission($page, ['view'], $roleB); + $this->assertVisibleToUser($page, $user); + } + + public function test_20_inherit_allow() + { + [$user, $roleA] = $this->users->newUserWithRole(); + $page = $this->entities->pageWithinChapter(); + $chapter = $page->chapter; + + $this->permissions->disableEntityInheritedPermissions($chapter); + $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + + $this->assertVisibleToUser($page, $user); + } + + public function test_21_inherit_deny() + { + [$user, $roleA] = $this->users->newUserWithRole(); + $page = $this->entities->pageWithinChapter(); + $chapter = $page->chapter; + + $this->permissions->disableEntityInheritedPermissions($chapter); + $this->permissions->addEntityPermission($chapter, [], $roleA); + + $this->assertNotVisibleToUser($page, $user); + } + + public function test_22_same_level_conflict_inherit() + { + [$user, $roleA] = $this->users->newUserWithRole(); + $roleB = $this->users->attachNewRole($user); + $page = $this->entities->pageWithinChapter(); + $chapter = $page->chapter; + + $this->permissions->disableEntityInheritedPermissions($chapter); + $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->addEntityPermission($chapter, ['view'], $roleB); + + $this->assertVisibleToUser($page, $user); + } + + public function test_30_child_inherit_override_allow() + { + [$user, $roleA] = $this->users->newUserWithRole(); + $page = $this->entities->pageWithinChapter(); + $chapter = $page->chapter; + + $this->permissions->disableEntityInheritedPermissions($chapter); + $this->permissions->addEntityPermission($chapter, [], $roleA); + $this->permissions->addEntityPermission($page, ['view'], $roleA); + + $this->assertVisibleToUser($page, $user); + } + + public function test_31_child_inherit_override_deny() + { + [$user, $roleA] = $this->users->newUserWithRole(); + $page = $this->entities->pageWithinChapter(); + $chapter = $page->chapter; + + $this->permissions->disableEntityInheritedPermissions($chapter); + $this->permissions->addEntityPermission($chapter, ['view'], $roleA); + $this->permissions->addEntityPermission($page, [], $roleA); + + $this->assertNotVisibleToUser($page, $user); + } + + protected function assertVisibleToUser(Entity $entity, User $user) + { $this->actingAs($user); - $this->assertTrue(userCan('page-view', $page)); - $this->assertNotNull(Page::visible()->find($page->id)); + $funcView = userCan($entity->getMorphClass() . '-view', $entity); + $queryView = $entity->newQuery()->scopes(['visible'])->find($entity->id) !== null; + + $id = $entity->getMorphClass() . ':' . $entity->id; + $msg = "Item [{$id}] should be visible but was not found via "; + $msg .= implode(' and ', array_filter([!$funcView ? 'userCan' : '', !$queryView ? 'query' : ''])); + + static::assertTrue($funcView && $queryView, $msg); + } + + protected function assertNotVisibleToUser(Entity $entity, User $user) + { + $this->actingAs($user); + $funcView = userCan($entity->getMorphClass() . '-view', $entity); + $queryView = $entity->newQuery()->scopes(['visible'])->find($entity->id) !== null; + + $id = $entity->getMorphClass() . ':' . $entity->id; + $msg = "Item [{$id}] should not be visible but was found via "; + $msg .= implode(' and ', array_filter([$funcView ? 'userCan' : '', $queryView ? 'query' : ''])); + + static::assertTrue(!$funcView && !$queryView, $msg); } }