createMock(PermissionService::class); $permissionService->expects($this->once()) ->method('userHas') ->with(4, PermissionService::SETTINGS_VIEW) ->willReturn(false); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_VIEW, [ 'actor_user_id' => 4, ]); $this->assertForbiddenDecision($decision); } public function testViewReturnsUpdateCapability(): void { $permissionService = $this->permissionGatewayAllowing([ 4 => [PermissionService::SETTINGS_VIEW, PermissionService::SETTINGS_UPDATE], ]); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_VIEW, [ 'actor_user_id' => 4, ]); $this->assertTrue($decision->isAllowed()); $this->assertTrue((bool) ($decision->attribute('capabilities', [])['can_update_settings'] ?? false)); } public function testUpdateRequiresSettingsUpdatePermission(): void { $permissionService = $this->createMock(PermissionService::class); $permissionService->expects($this->once()) ->method('userHas') ->with(8, PermissionService::SETTINGS_UPDATE) ->willReturn(false); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE, [ 'actor_user_id' => 8, ]); $this->assertDeniedDecision($decision, 403, 'forbidden'); } public function testBrandingUpdateRequiresSettingsUpdatePermission(): void { $permissionService = $this->createMock(PermissionService::class); $permissionService->expects($this->once()) ->method('userHas') ->with(8, PermissionService::SETTINGS_UPDATE) ->willReturn(false); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_BRANDING_UPDATE, [ 'actor_user_id' => 8, ]); $this->assertDeniedDecision($decision, 403, 'forbidden'); } public function testTokenRevokeRequiresSettingsUpdatePermission(): void { $permissionService = $this->createMock(PermissionService::class); $permissionService->expects($this->once()) ->method('userHas') ->with(8, PermissionService::SETTINGS_UPDATE) ->willReturn(false); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_TOKENS_REVOKE, [ 'actor_user_id' => 8, ]); $this->assertDeniedDecision($decision, 403, 'forbidden'); } public function testUserLifecycleRunRequiresSettingsUpdatePermission(): void { $permissionService = $this->createMock(PermissionService::class); $permissionService->expects($this->once()) ->method('userHas') ->with(8, PermissionService::SETTINGS_UPDATE) ->willReturn(false); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_USER_LIFECYCLE_RUN, [ 'actor_user_id' => 8, ]); $this->assertDeniedDecision($decision, 403, 'forbidden'); } public function testUpdateAllowsWhenPermissionGranted(): void { $permissionService = $this->permissionGatewayAllowing([ 8 => [PermissionService::SETTINGS_UPDATE], ]); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE, [ 'actor_user_id' => 8, ]); $this->assertTrue($decision->isAllowed()); } public function testBrandingUpdateAllowsWhenPermissionGranted(): void { $permissionService = $this->permissionGatewayAllowing([ 8 => [PermissionService::SETTINGS_UPDATE], ]); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_BRANDING_UPDATE, [ 'actor_user_id' => 8, ]); $this->assertTrue($decision->isAllowed()); } public function testTokenRevokeAllowsWhenPermissionGranted(): void { $permissionService = $this->permissionGatewayAllowing([ 8 => [PermissionService::SETTINGS_UPDATE], ]); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_TOKENS_REVOKE, [ 'actor_user_id' => 8, ]); $this->assertTrue($decision->isAllowed()); } public function testUserLifecycleRunAllowsWhenPermissionGranted(): void { $permissionService = $this->permissionGatewayAllowing([ 8 => [PermissionService::SETTINGS_UPDATE], ]); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize(SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_USER_LIFECYCLE_RUN, [ 'actor_user_id' => 8, ]); $this->assertTrue($decision->isAllowed()); } public function testUnknownAbilityIsDeniedWithServerError(): void { $permissionService = $this->createMock(PermissionService::class); $permissionService->expects($this->never())->method('userHas'); $policy = new SettingsAuthorizationPolicy($permissionService); $decision = $policy->authorize('admin.settings.nonexistent', [ 'actor_user_id' => 8, ]); $this->assertDeniedDecision($decision, 500, 'authorization_ability_not_supported'); } }