weitere updates für instanzierbarkeit und sauberes testing
This commit is contained in:
455
lib/Service/Access/UserAuthorizationPolicy.php
Normal file
455
lib/Service/Access/UserAuthorizationPolicy.php
Normal file
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\Access;
|
||||
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
|
||||
class UserAuthorizationPolicy implements AuthorizationPolicyInterface
|
||||
{
|
||||
public const ABILITY_ADMIN_USERS_VIEW = 'admin.users.view';
|
||||
public const ABILITY_ADMIN_USERS_CREATE = 'admin.users.create';
|
||||
public const ABILITY_ADMIN_USERS_EDIT_CONTEXT = 'admin.users.edit.context';
|
||||
public const ABILITY_ADMIN_USERS_EDIT_SUBMIT = 'admin.users.edit.submit';
|
||||
public const ABILITY_ADMIN_USERS_ACTIVATE = 'admin.users.activate';
|
||||
public const ABILITY_ADMIN_USERS_DEACTIVATE = 'admin.users.deactivate';
|
||||
public const ABILITY_ADMIN_USERS_DELETE = 'admin.users.delete';
|
||||
public const ABILITY_ADMIN_USERS_BULK = 'admin.users.bulk';
|
||||
public const ABILITY_ADMIN_USERS_ACCESS_PDF = 'admin.users.access_pdf';
|
||||
public const ABILITY_ADMIN_USERS_ACCESS_PDF_BULK = 'admin.users.access_pdf_bulk';
|
||||
public const ABILITY_ADMIN_USERS_AVATAR_UPLOAD = 'admin.users.avatar.upload';
|
||||
public const ABILITY_ADMIN_USERS_AVATAR_DELETE = 'admin.users.avatar.delete';
|
||||
public const ABILITY_ADMIN_USERS_AVATAR_VIEW = 'admin.users.avatar.view';
|
||||
public const ABILITY_ADMIN_USERS_API_TOKENS_MANAGE = 'admin.users.api_tokens_manage';
|
||||
public const ABILITY_ADMIN_USERS_SEND_ACCESS = 'admin.users.send_access';
|
||||
public const ABILITY_ADMIN_USERS_FORGET_TOKENS = 'admin.users.forget_tokens';
|
||||
public const ABILITY_API_USERS_INDEX_GET = 'api.users.index.get';
|
||||
public const ABILITY_API_USERS_INDEX_POST = 'api.users.index.post';
|
||||
public const ABILITY_API_USERS_SHOW_GET = 'api.users.show.get';
|
||||
public const ABILITY_API_USERS_SHOW_UPDATE = 'api.users.show.update';
|
||||
public const ABILITY_API_USERS_SHOW_DELETE = 'api.users.show.delete';
|
||||
|
||||
public function __construct(
|
||||
private readonly PermissionGateway $permissionGateway,
|
||||
private readonly DirectoryScopeGateway $scopeGateway
|
||||
) {
|
||||
}
|
||||
|
||||
public function supports(string $ability): bool
|
||||
{
|
||||
return in_array($ability, [
|
||||
self::ABILITY_ADMIN_USERS_VIEW,
|
||||
self::ABILITY_ADMIN_USERS_CREATE,
|
||||
self::ABILITY_ADMIN_USERS_EDIT_CONTEXT,
|
||||
self::ABILITY_ADMIN_USERS_EDIT_SUBMIT,
|
||||
self::ABILITY_ADMIN_USERS_ACTIVATE,
|
||||
self::ABILITY_ADMIN_USERS_DEACTIVATE,
|
||||
self::ABILITY_ADMIN_USERS_DELETE,
|
||||
self::ABILITY_ADMIN_USERS_BULK,
|
||||
self::ABILITY_ADMIN_USERS_ACCESS_PDF,
|
||||
self::ABILITY_ADMIN_USERS_ACCESS_PDF_BULK,
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_UPLOAD,
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_DELETE,
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_VIEW,
|
||||
self::ABILITY_ADMIN_USERS_API_TOKENS_MANAGE,
|
||||
self::ABILITY_ADMIN_USERS_SEND_ACCESS,
|
||||
self::ABILITY_ADMIN_USERS_FORGET_TOKENS,
|
||||
self::ABILITY_API_USERS_INDEX_GET,
|
||||
self::ABILITY_API_USERS_INDEX_POST,
|
||||
self::ABILITY_API_USERS_SHOW_GET,
|
||||
self::ABILITY_API_USERS_SHOW_UPDATE,
|
||||
self::ABILITY_API_USERS_SHOW_DELETE,
|
||||
], true);
|
||||
}
|
||||
|
||||
public function authorize(string $ability, array $context = []): AuthorizationDecision
|
||||
{
|
||||
return match ($ability) {
|
||||
self::ABILITY_ADMIN_USERS_VIEW => $this->authorizeAdminUsersView($context),
|
||||
self::ABILITY_ADMIN_USERS_CREATE => $this->authorizeAdminUsersCreate($context),
|
||||
self::ABILITY_ADMIN_USERS_EDIT_CONTEXT => $this->authorizeAdminUsersEditContext($context),
|
||||
self::ABILITY_ADMIN_USERS_EDIT_SUBMIT => $this->authorizeAdminUsersEditSubmit($context),
|
||||
self::ABILITY_ADMIN_USERS_ACTIVATE,
|
||||
self::ABILITY_ADMIN_USERS_DEACTIVATE => $this->authorizeAdminUserStatusUpdate($context),
|
||||
self::ABILITY_ADMIN_USERS_DELETE => $this->authorizeAdminUserDelete($context),
|
||||
self::ABILITY_ADMIN_USERS_BULK => $this->authorizeAdminUsersBulk($context),
|
||||
self::ABILITY_ADMIN_USERS_ACCESS_PDF => $this->authorizeAdminUserAccessPdf($context),
|
||||
self::ABILITY_ADMIN_USERS_ACCESS_PDF_BULK => $this->authorizeAdminUsersAccessPdfBulk($context),
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_UPLOAD,
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_DELETE => $this->authorizeAdminUsersAvatarMutate($context),
|
||||
self::ABILITY_ADMIN_USERS_AVATAR_VIEW => $this->authorizeAdminUsersAvatarView($context),
|
||||
self::ABILITY_ADMIN_USERS_API_TOKENS_MANAGE => $this->authorizeAdminUsersApiTokensManage($context),
|
||||
self::ABILITY_ADMIN_USERS_SEND_ACCESS,
|
||||
self::ABILITY_ADMIN_USERS_FORGET_TOKENS => $this->authorizeAdminUserSelfOrUpdate($context),
|
||||
self::ABILITY_API_USERS_INDEX_GET => $this->authorizeApiUsersIndexGet($context),
|
||||
self::ABILITY_API_USERS_INDEX_POST => $this->authorizeApiUsersIndexPost($context),
|
||||
self::ABILITY_API_USERS_SHOW_GET => $this->authorizeApiUsersShow($context, PermissionService::USERS_VIEW),
|
||||
self::ABILITY_API_USERS_SHOW_UPDATE => $this->authorizeApiUsersUpdate($context),
|
||||
self::ABILITY_API_USERS_SHOW_DELETE => $this->authorizeApiUsersShow($context, PermissionService::USERS_DELETE),
|
||||
default => AuthorizationDecision::deny(500, 'authorization_ability_not_supported'),
|
||||
};
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersView(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_VIEW, $context, false);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersCreate(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_CREATE, $context, false);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersEditContext(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->buildEditContextDecision($context);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersEditSubmit(array $context): AuthorizationDecision
|
||||
{
|
||||
$contextDecision = $this->buildEditContextDecision($context);
|
||||
if (!$contextDecision->isAllowed()) {
|
||||
return $contextDecision;
|
||||
}
|
||||
|
||||
$capabilities = $this->capabilitiesFromDecision($contextDecision);
|
||||
if (!($capabilities['can_edit_user'] ?? false)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow(['capabilities' => $capabilities]);
|
||||
}
|
||||
|
||||
private function authorizeAdminUserStatusUpdate(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_UPDATE, $context);
|
||||
}
|
||||
|
||||
private function authorizeAdminUserDelete(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_DELETE, $context);
|
||||
}
|
||||
|
||||
private function authorizeAdminUserAccessPdf(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_ACCESS_PDF, $context);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersAccessPdfBulk(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::USERS_ACCESS_PDF, $context, false);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersApiTokensManage(array $context): AuthorizationDecision
|
||||
{
|
||||
return $this->authorizeAdminUserWithPermission(PermissionService::API_TOKENS_MANAGE, $context);
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersAvatarMutate(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($actorUserId <= 0 || $targetUserId <= 0) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
$isOwnAccount = $actorUserId === $targetUserId;
|
||||
if (!$isOwnAccount && !$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(403, 'permission_denied');
|
||||
}
|
||||
|
||||
$canEditUser = $this->canEditUserForTarget($actorUserId, $targetUserId);
|
||||
if (!$canEditUser) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersAvatarView(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($actorUserId <= 0 || $targetUserId <= 0) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
if ($actorUserId === $targetUserId) {
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
if (!$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(403, 'permission_denied');
|
||||
}
|
||||
|
||||
$canEditUser = $this->canEditUserForTarget($actorUserId, $targetUserId);
|
||||
if (!$this->hasPermission($actorUserId, PermissionService::USERS_VIEW)
|
||||
&& !$this->hasPermission($actorUserId, PermissionService::ADDRESS_BOOK_VIEW)
|
||||
&& !$canEditUser) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
private function authorizeAdminUserSelfOrUpdate(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($targetUserId <= 0) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
if ($this->canEditUserForTarget($actorUserId, $targetUserId)) {
|
||||
if ($targetUserId !== $actorUserId
|
||||
&& !$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(403, 'permission_denied');
|
||||
}
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
private function authorizeAdminUsersBulk(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
$action = strtolower(trim((string) ($context['bulk_action'] ?? '')));
|
||||
|
||||
$permission = match ($action) {
|
||||
'delete' => PermissionService::USERS_DELETE,
|
||||
'activate', 'deactivate', 'send-access' => PermissionService::USERS_UPDATE,
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($permission === null) {
|
||||
return AuthorizationDecision::deny(400, 'invalid_action');
|
||||
}
|
||||
if (!$this->hasPermission($actorUserId, $permission)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
private function authorizeApiUsersIndexGet(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
if (!$this->hasPermission($actorUserId, PermissionService::USERS_VIEW)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
private function authorizeApiUsersIndexPost(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
if (!$this->hasPermission($actorUserId, PermissionService::USERS_CREATE)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
$input = is_array($context['input'] ?? null) ? $context['input'] : [];
|
||||
$scopedTenantId = (int) ($context['scoped_tenant_id'] ?? 0);
|
||||
if ($scopedTenantId <= 0) {
|
||||
return AuthorizationDecision::allow(['input' => $input]);
|
||||
}
|
||||
|
||||
if ($this->containsOutOfScopeTenantId($input['tenant_ids'] ?? [], $scopedTenantId)) {
|
||||
return AuthorizationDecision::deny(403, 'tenant_scoped_token_forbidden');
|
||||
}
|
||||
|
||||
$primaryTenantId = (int) ($input['primary_tenant_id'] ?? 0);
|
||||
if ($primaryTenantId > 0 && $primaryTenantId !== $scopedTenantId) {
|
||||
return AuthorizationDecision::deny(403, 'tenant_scoped_token_forbidden');
|
||||
}
|
||||
|
||||
$input['tenant_ids'] = [$scopedTenantId];
|
||||
$input['primary_tenant_id'] = $scopedTenantId;
|
||||
|
||||
return AuthorizationDecision::allow(['input' => $input]);
|
||||
}
|
||||
|
||||
private function authorizeApiUsersUpdate(array $context): AuthorizationDecision
|
||||
{
|
||||
$decision = $this->authorizeApiUsersShow($context, PermissionService::USERS_UPDATE);
|
||||
if (!$decision->isAllowed()) {
|
||||
return $decision;
|
||||
}
|
||||
|
||||
$input = is_array($context['input'] ?? null) ? $context['input'] : [];
|
||||
$scopedTenantId = (int) ($context['scoped_tenant_id'] ?? 0);
|
||||
if ($scopedTenantId <= 0) {
|
||||
return AuthorizationDecision::allow(['input' => $input]);
|
||||
}
|
||||
|
||||
if (array_key_exists('tenant_ids', $input)
|
||||
&& $this->containsOutOfScopeTenantId($input['tenant_ids'], $scopedTenantId)) {
|
||||
return AuthorizationDecision::deny(403, 'tenant_scoped_token_forbidden');
|
||||
}
|
||||
|
||||
if (array_key_exists('primary_tenant_id', $input)) {
|
||||
$primaryTenantId = (int) ($input['primary_tenant_id'] ?? 0);
|
||||
if ($primaryTenantId > 0 && $primaryTenantId !== $scopedTenantId) {
|
||||
return AuthorizationDecision::deny(403, 'tenant_scoped_token_forbidden');
|
||||
}
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow(['input' => $input]);
|
||||
}
|
||||
|
||||
private function authorizeApiUsersShow(array $context, string $permissionKey): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
if (!$this->hasPermission($actorUserId, $permissionKey)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($targetUserId <= 0) {
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
if (!$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(404, 'not_found');
|
||||
}
|
||||
|
||||
$scopedTenantId = (int) ($context['scoped_tenant_id'] ?? 0);
|
||||
if ($scopedTenantId > 0 && !$this->scopeGateway->resourceBelongsToTenant('users', $targetUserId, $scopedTenantId)) {
|
||||
return AuthorizationDecision::deny(404, 'not_found');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
private function containsOutOfScopeTenantId(mixed $tenantIdsRaw, int $scopedTenantId): bool
|
||||
{
|
||||
$tenantIds = $this->normalizeTenantIds($tenantIdsRaw);
|
||||
if (!$tenantIds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array_diff($tenantIds, [$scopedTenantId]) !== [];
|
||||
}
|
||||
|
||||
private function normalizeTenantIds(mixed $tenantIdsRaw): array
|
||||
{
|
||||
if (!is_array($tenantIdsRaw)) {
|
||||
$tenantIdsRaw = [$tenantIdsRaw];
|
||||
}
|
||||
|
||||
$tenantIds = [];
|
||||
foreach ($tenantIdsRaw as $value) {
|
||||
$tenantId = (int) $value;
|
||||
if ($tenantId > 0) {
|
||||
$tenantIds[$tenantId] = $tenantId;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($tenantIds);
|
||||
}
|
||||
|
||||
private function actorUserId(array $context): int
|
||||
{
|
||||
return (int) ($context['actor_user_id'] ?? 0);
|
||||
}
|
||||
|
||||
private function hasPermission(int $userId, string $permissionKey): bool
|
||||
{
|
||||
return $userId > 0 && $this->permissionGateway->userHas($userId, $permissionKey);
|
||||
}
|
||||
|
||||
private function canEditUserForTarget(int $actorUserId, int $targetUserId): bool
|
||||
{
|
||||
if ($actorUserId <= 0 || $targetUserId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$canUpdateUser = $this->hasPermission($actorUserId, PermissionService::USERS_UPDATE);
|
||||
if ($targetUserId === $actorUserId) {
|
||||
return $canUpdateUser || $this->hasPermission($actorUserId, PermissionService::USERS_SELF_UPDATE);
|
||||
}
|
||||
|
||||
return $canUpdateUser;
|
||||
}
|
||||
|
||||
private function buildEditContextDecision(array $context): AuthorizationDecision
|
||||
{
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($actorUserId <= 0 || $targetUserId <= 0) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
$isOwnAccount = $targetUserId === $actorUserId;
|
||||
if (!$isOwnAccount && !$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(403, 'permission_denied');
|
||||
}
|
||||
|
||||
$canViewUsers = $this->hasPermission($actorUserId, PermissionService::USERS_VIEW);
|
||||
$canEditUser = $this->canEditUserForTarget($actorUserId, $targetUserId);
|
||||
$canViewPage = $canViewUsers || $canEditUser;
|
||||
if (!$canViewPage) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
$canManageTenants = $this->hasPermission($actorUserId, PermissionService::TENANTS_UPDATE);
|
||||
$allowedTenantIds = $canManageTenants ? null : $this->scopeGateway->getUserTenantIds($actorUserId);
|
||||
$canViewUserAudit = $this->hasPermission($actorUserId, PermissionService::USERS_VIEW_AUDIT);
|
||||
|
||||
$capabilities = [
|
||||
'can_view_page' => $canViewPage,
|
||||
'can_view_users' => $canViewUsers,
|
||||
'can_edit_user' => $canEditUser,
|
||||
'can_edit_assignments' => $canEditUser && $this->hasPermission($actorUserId, PermissionService::USERS_UPDATE_ASSIGNMENTS),
|
||||
'can_manage_tenants' => $canManageTenants,
|
||||
'can_edit_custom_field_values' => $canEditUser && (
|
||||
$this->hasPermission($actorUserId, PermissionService::CUSTOM_FIELDS_EDIT_VALUES)
|
||||
|| ($isOwnAccount && $this->hasPermission($actorUserId, PermissionService::USERS_SELF_UPDATE))
|
||||
),
|
||||
'can_manage_api_tokens' => $canEditUser && $this->hasPermission($actorUserId, PermissionService::API_TOKENS_MANAGE),
|
||||
'can_view_address_book' => $this->hasPermission($actorUserId, PermissionService::ADDRESS_BOOK_VIEW),
|
||||
'can_view_user_meta' => $this->hasPermission($actorUserId, PermissionService::USERS_VIEW_META),
|
||||
'can_view_user_audit' => $canViewUserAudit,
|
||||
'can_access_pdf' => $this->hasPermission($actorUserId, PermissionService::USERS_ACCESS_PDF),
|
||||
'can_delete_user' => !$isOwnAccount && $this->hasPermission($actorUserId, PermissionService::USERS_DELETE),
|
||||
'can_view_security_artifacts' => $isOwnAccount || $canViewUserAudit,
|
||||
'can_view_permissions_table' => $this->hasPermission($actorUserId, PermissionService::PERMISSIONS_VIEW),
|
||||
'is_own_account' => $isOwnAccount,
|
||||
'allowed_tenant_ids' => is_array($allowedTenantIds)
|
||||
? array_values(array_unique(array_map('intval', $allowedTenantIds)))
|
||||
: null,
|
||||
];
|
||||
|
||||
return AuthorizationDecision::allow(['capabilities' => $capabilities]);
|
||||
}
|
||||
|
||||
private function capabilitiesFromDecision(AuthorizationDecision $decision): array
|
||||
{
|
||||
$capabilities = $decision->attribute('capabilities', []);
|
||||
return is_array($capabilities) ? $capabilities : [];
|
||||
}
|
||||
|
||||
private function authorizeAdminUserWithPermission(
|
||||
string $permissionKey,
|
||||
array $context,
|
||||
bool $checkTenantScope = true
|
||||
): AuthorizationDecision {
|
||||
$actorUserId = $this->actorUserId($context);
|
||||
if (!$this->hasPermission($actorUserId, $permissionKey)) {
|
||||
return AuthorizationDecision::deny(403, 'forbidden');
|
||||
}
|
||||
|
||||
if (!$checkTenantScope) {
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
|
||||
$targetUserId = (int) ($context['target_user_id'] ?? 0);
|
||||
if ($targetUserId > 0
|
||||
&& $targetUserId !== $actorUserId
|
||||
&& !$this->scopeGateway->canAccess('users', $targetUserId, $actorUserId)) {
|
||||
return AuthorizationDecision::deny(403, 'permission_denied');
|
||||
}
|
||||
|
||||
return AuthorizationDecision::allow();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user