Skip to content

Commit

Permalink
Add wildcard support for permission restrictions
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuelWei committed Dec 17, 2024
1 parent 595d639 commit ad4338e
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 17 deletions.
13 changes: 2 additions & 11 deletions app/Http/Controllers/api/v1/RoleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\RoleRequest;
use App\Http\Resources\Role as RoleResource;
use App\Models\Permission;
use App\Models\Role;
use App\Settings\GeneralSettings;
use Exception;
Expand Down Expand Up @@ -74,11 +73,7 @@ public function store(RoleRequest $request)

$role->save();

$new_permissions = collect($request->permissions)->filter(function ($permissionId) {
$permission = Permission::find($permissionId);

return ! in_array($permission->name, config('permissions.restrictions'));
});
$new_permissions = $role->filterRestrictedPermissions(collect($request->permissions));

$role->permissions()->sync($new_permissions);

Expand Down Expand Up @@ -106,11 +101,7 @@ public function update(RoleRequest $request, Role $role)
if (! $role->superuser) {
$old_role_permissions = $role->permissions()->pluck('permissions.id')->toArray();

$new_permissions = collect($request->permissions)->filter(function ($permissionId) {
$permission = Permission::find($permissionId);

return ! in_array($permission->name, config('permissions.restrictions'));
});
$new_permissions = $role->filterRestrictedPermissions(collect($request->permissions));

$role->permissions()->sync($new_permissions);

Expand Down
37 changes: 37 additions & 0 deletions app/Models/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;

/**
* Class Role
Expand Down Expand Up @@ -46,6 +47,42 @@ public function permissions()
return $this->belongsToMany(Permission::class)->using(PermissionRole::class);
}

/**
* Filters out restricted permissions from the given collection of permission IDs.
*
* @param Collection $permissionIDs Collection of permission IDs to be filtered.
* @return Collection Filtered collection of permission IDs that are not restricted.
*/
public function filterRestrictedPermissions(Collection $permissionIDs): Collection
{
return $permissionIDs->filter(function ($permissionID) {
// Find the permission by its ID
$permission = Permission::find($permissionID);
if ($permission === null) {
return false;
}

// Get the list of restricted permissions from the configuration
$restrictions = collect(config('permissions.restrictions'));

// Check if the permission is not in the list of restricted permissions
return $restrictions->doesntContain(function (string $restriction) use ($permission) {
// If the restriction matches the permission name, it is restricted
if ($restriction === $permission->name) {
return true;
}

// Split the restriction and permission names into groups and permissions
$restrictionGroup = explode('.', $restriction, 2)[0];
$restrictionPermission = explode('.', $restriction, 2)[1] ?? null;
$permissionGroup = explode('.', $permission->name, 2)[0];

// If the restriction applies to all permissions in the group, it is restricted
return $restrictionPermission === '*' && $restrictionGroup === $permissionGroup;
});
});
}

/**
* Types of rooms that can be used by the user of this role.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ To prevent regular admins from managing certain permissions:
Example (regular admins cannot manage servers or server pools):

```bash
PERMISSION_RESTRICTIONS=servers.viewAny,servers.view,servers.create,servers.update,servers.delete,serverPools.viewAny,serverPools.view,serverPools.create,serverPools.update,serverPools.delete
PERMISSION_RESTRICTIONS=servers.*,serverPools.viewAny,serverPools.view,serverPools.create,serverPools.update,serverPools.delete
```

The permissions can either be a specific permission or a wildcard `*` to restrict all permissions of a group.

Permissions in this list cannot be assigned to roles by anyone except superusers.
20 changes: 18 additions & 2 deletions resources/js/views/AdminRolesView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,24 @@ function loadPermissions() {
response.data.data.forEach((permission) => {
permission.rawName = permission.name;
permission.restricted = permissionRestrictions.value.includes(
permission.name,
permission.restricted = permissionRestrictions.value.some(
(restriction) => {
if (restriction === permission.name) {
return true;
}
return false;
const restrictionPermission = restriction.split(".", 2)[1];
const restrictionGroup = restriction.split(".", 2)[0];
const permissionGroup = permission.name.split(".", 2)[0];
return (
restrictionPermission === "*" &&
permissionGroup === restrictionGroup
);
},
);
permission.name = permission.name
Expand Down
7 changes: 4 additions & 3 deletions tests/Backend/Feature/api/v1/RoleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,15 @@ public function test_create()
public function test_create_restricted_permissions()
{

config(['permissions.restrictions' => ['servers.create']]);
config(['permissions.restrictions' => ['servers.create', 'serverPools.*']]);

$user = User::factory()->create();
$roleA = Role::factory()->create();
$user->roles()->attach([$roleA->id]);

$createRolesPermission = Permission::firstOrCreate(['name' => 'roles.create']);
$createServersPermission = Permission::firstOrCreate(['name' => 'servers.create']);
$createServerPoolPermission = Permission::firstOrCreate(['name' => 'serverPools.create']);
$roleA->permissions()->attach([$createRolesPermission, $createServersPermission]);

$role = [
Expand Down Expand Up @@ -274,7 +275,7 @@ public function test_update_restricted_permissions()
$roleA = Role::factory()->create();
$user->roles()->attach([$roleA->id]);

config(['permissions.restrictions' => ['servers.create']]);
config(['permissions.restrictions' => ['servers.create', 'serverPools.*']]);

$permission_ids = [
Permission::firstOrCreate(['name' => 'admin.view'])->id,
Expand All @@ -294,7 +295,7 @@ public function test_update_restricted_permissions()
$role = [
'name' => 'Test',
'superuser' => false,
'permissions' => [...$permission_ids, $createServersPermission->id],
'permissions' => [...$permission_ids, $createServerPoolsPermission->id, $createServersPermission->id],
'room_limit' => 1,
'updated_at' => now(),
];
Expand Down

0 comments on commit ad4338e

Please sign in to comment.