Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/Auth/Eloquent/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,15 @@ public function permissions()

public function hasPermission($permission)
{
return $this->permissions()->contains($permission);
$permissions = $this->permissions();

if ($permissions->contains($permission)) {
return true;
}

return $permissions->contains(function ($userPermission) use ($permission) {
return $this->matchesWildcard($userPermission, $permission);
});
}

public function makeSuper()
Expand Down Expand Up @@ -402,4 +410,17 @@ public function getCurrentDirtyStateAttributes(): array
'email' => $this->email(),
], $this->model()->attributesToArray());
}

protected function matchesWildcard(string $wildcardPermission, string $requestedPermission): bool
{
if (! str_contains($wildcardPermission, '*')) {
return false;
}

$pattern = preg_quote($wildcardPermission, '/');
$pattern = str_replace('\*', '.*', $pattern);
$pattern = '/^'.$pattern.'$/';

return (bool) preg_match($pattern, $requestedPermission);
}
}
21 changes: 20 additions & 1 deletion src/Auth/File/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ public function removePermission($permission)

public function hasPermission(string $permission): bool
{
return $this->permissions->contains($permission);
if ($this->permissions->contains($permission)) {
return true;
}

return $this->permissions->contains(function ($rolePermission) use ($permission) {
return $this->matchesWildcard($rolePermission, $permission);
});
}

public function isSuper(): bool
Expand All @@ -125,4 +131,17 @@ public function delete()

RoleDeleted::dispatch($this);
}

protected function matchesWildcard(string $wildcardPermission, string $requestedPermission): bool
{
if (! str_contains($wildcardPermission, '*')) {
return false;
}

$pattern = preg_quote($wildcardPermission, '/');
$pattern = str_replace('\*', '.*', $pattern);
$pattern = '/^'.$pattern.'$/';

return (bool) preg_match($pattern, $requestedPermission);
}
}
23 changes: 22 additions & 1 deletion src/Auth/File/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,15 @@ public function permissions()

public function hasPermission($permission)
{
return $this->permissions()->contains($permission);
$permissions = $this->permissions();

if ($permissions->contains($permission)) {
return true;
}

return $permissions->contains(function ($userPermission) use ($permission) {
return $this->matchesWildcard($userPermission, $permission);
});
}

public function makeSuper()
Expand Down Expand Up @@ -377,4 +385,17 @@ public function getCurrentDirtyStateAttributes(): array
'super' => $this->get('super', false),
], $this->data()->toArray());
}

protected function matchesWildcard(string $wildcardPermission, string $requestedPermission): bool
{
if (! str_contains($wildcardPermission, '*')) {
return false;
}

$pattern = preg_quote($wildcardPermission, '/');
$pattern = str_replace('\*', '.*', $pattern);
$pattern = '/^'.$pattern.'$/';

return (bool) preg_match($pattern, $requestedPermission);
}
}
25 changes: 23 additions & 2 deletions src/Auth/UserGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,17 @@ public function hasRole($role): bool

public function hasPermission($permission)
{
return $this->roles->reduce(function ($carry, $role) {
$permissions = $this->roles->reduce(function ($carry, $role) {
return $carry->merge($role->permissions());
}, collect())->contains($permission);
}, collect());

if ($permissions->contains($permission)) {
return true;
}

return $permissions->contains(function ($groupPermission) use ($permission) {
return $this->matchesWildcard($groupPermission, $permission);
});
}

public function isSuper(): bool
Expand Down Expand Up @@ -201,4 +209,17 @@ public function blueprint()
{
return Facades\UserGroup::blueprint();
}

protected function matchesWildcard(string $wildcardPermission, string $requestedPermission): bool
{
if (! str_contains($wildcardPermission, '*')) {
return false;
}

$pattern = preg_quote($wildcardPermission, '/');
$pattern = str_replace('\*', '.*', $pattern);
$pattern = '/^'.$pattern.'$/';

return (bool) preg_match($pattern, $requestedPermission);
}
}
81 changes: 81 additions & 0 deletions tests/Auth/PermissibleContractTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -363,4 +363,85 @@ public function it_sets_all_the_groups()
'c' => 'c',
], $user->groups()->map->handle()->all());
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_at_beginning()
{
$role = RoleAPI::make('test')->addPermission('* blog entries');
RoleAPI::shouldReceive('find')->with('test')->andReturn($role);
RoleAPI::shouldReceive('all')->andReturn(collect([$role]));

$user = $this->createPermissible()->assignRole($role);
$user->save();

$this->assertTrue($user->hasPermission('view blog entries'));
$this->assertTrue($user->hasPermission('edit blog entries'));
$this->assertTrue($user->hasPermission('delete blog entries'));
$this->assertFalse($user->hasPermission('view news entries'));
$this->assertFalse($user->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_in_middle()
{
$role = RoleAPI::make('test')->addPermission('view * entries');
RoleAPI::shouldReceive('find')->with('test')->andReturn($role);
RoleAPI::shouldReceive('all')->andReturn(collect([$role]));

$user = $this->createPermissible()->assignRole($role);
$user->save();

$this->assertTrue($user->hasPermission('view blog entries'));
$this->assertTrue($user->hasPermission('view news entries'));
$this->assertTrue($user->hasPermission('view products entries'));
$this->assertFalse($user->hasPermission('edit blog entries'));
$this->assertFalse($user->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_wildcard_permission_through_user_group()
{
$role = RoleAPI::make('test')->addPermission('view * entries');
$userGroup = (new UserGroup)->handle('testgroup')->assignRole($role);

RoleAPI::shouldReceive('find')->with('test')->andReturn($role);
RoleAPI::shouldReceive('all')->andReturn(collect([$role]));
UserGroupAPI::shouldReceive('find')->with('testgroup')->andReturn($userGroup);
UserGroupAPI::shouldReceive('all')->andReturn(collect([$userGroup]));

$user = $this->createPermissible()->addToGroup($userGroup);
$user->save();

$this->assertTrue($user->hasPermission('view blog entries'));
$this->assertTrue($user->hasPermission('view news entries'));
$this->assertTrue($user->hasPermission('view products entries'));
$this->assertFalse($user->hasPermission('edit blog entries'));
$this->assertFalse($user->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_multiple_wildcard_permissions_from_different_sources()
{
$directRole = RoleAPI::make('direct')->addPermission('view * entries');
$groupRole = RoleAPI::make('grouprole')->addPermission('* blog entries');
$userGroup = (new UserGroup)->handle('testgroup')->assignRole($groupRole);

RoleAPI::shouldReceive('find')->with('direct')->andReturn($directRole);
RoleAPI::shouldReceive('find')->with('grouprole')->andReturn($groupRole);
RoleAPI::shouldReceive('all')->andReturn(collect([$directRole, $groupRole]));
UserGroupAPI::shouldReceive('find')->with('testgroup')->andReturn($userGroup);
UserGroupAPI::shouldReceive('all')->andReturn(collect([$userGroup]));

$user = $this->createPermissible()
->assignRole($directRole)
->addToGroup($userGroup);
$user->save();

$this->assertTrue($user->hasPermission('view blog entries'));
$this->assertTrue($user->hasPermission('view news entries'));
$this->assertTrue($user->hasPermission('edit blog entries'));
$this->assertTrue($user->hasPermission('delete blog entries'));
$this->assertFalse($user->hasPermission('delete news entries'));
$this->assertFalse($user->hasPermission('view blog posts'));
}
}
39 changes: 39 additions & 0 deletions tests/Auth/RoleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,45 @@ public function it_checks_if_it_has_permission()
$this->assertFalse($role->hasPermission('bar'));
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_at_beginning()
{
$role = (new Role)->addPermission('* blog entries');

$this->assertTrue($role->hasPermission('view blog entries'));
$this->assertTrue($role->hasPermission('edit blog entries'));
$this->assertTrue($role->hasPermission('delete blog entries'));
$this->assertFalse($role->hasPermission('view news entries'));
$this->assertFalse($role->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_in_middle()
{
$role = (new Role)->addPermission('view * entries');

$this->assertTrue($role->hasPermission('view blog entries'));
$this->assertTrue($role->hasPermission('view news entries'));
$this->assertTrue($role->hasPermission('view products entries'));
$this->assertFalse($role->hasPermission('edit blog entries'));
$this->assertFalse($role->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_multiple_wildcard_permissions()
{
$role = (new Role)
->addPermission('view * entries')
->addPermission('* blog entries');

$this->assertTrue($role->hasPermission('view blog entries'));
$this->assertTrue($role->hasPermission('view news entries'));
$this->assertTrue($role->hasPermission('edit blog entries'));
$this->assertTrue($role->hasPermission('delete blog entries'));
$this->assertFalse($role->hasPermission('delete news entries'));
$this->assertFalse($role->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_if_it_has_super_permissions()
{
Expand Down
81 changes: 81 additions & 0 deletions tests/Auth/UserGroupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,87 @@ public function permissions($permissions = null)
$this->assertFalse($group->hasPermission('two'));
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_at_beginning()
{
$role = new class extends Role
{
public function permissions($permissions = null)
{
return collect(['* blog entries']);
}
};

$group = UserGroup::make()->assignRole($role);

$this->assertTrue($group->hasPermission('view blog entries'));
$this->assertTrue($group->hasPermission('edit blog entries'));
$this->assertTrue($group->hasPermission('delete blog entries'));
$this->assertFalse($group->hasPermission('view news entries'));
$this->assertFalse($group->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_wildcard_permission_with_asterisk_in_middle()
{
$role = new class extends Role
{
public function permissions($permissions = null)
{
return collect(['view * entries']);
}
};

$group = UserGroup::make()->assignRole($role);

$this->assertTrue($group->hasPermission('view blog entries'));
$this->assertTrue($group->hasPermission('view news entries'));
$this->assertTrue($group->hasPermission('view products entries'));
$this->assertFalse($group->hasPermission('edit blog entries'));
$this->assertFalse($group->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_multiple_roles_with_wildcard_permissions()
{
$roleOne = new class extends Role
{
public function handle(?string $handle = null)
{
return 'role_one';
}

public function permissions($permissions = null)
{
return collect(['view * entries']);
}
};

$roleTwo = new class extends Role
{
public function handle(?string $handle = null)
{
return 'role_two';
}

public function permissions($permissions = null)
{
return collect(['* blog entries']);
}
};

$group = UserGroup::make()
->assignRole($roleOne)
->assignRole($roleTwo);

$this->assertTrue($group->hasPermission('view blog entries'));
$this->assertTrue($group->hasPermission('view news entries'));
$this->assertTrue($group->hasPermission('edit blog entries'));
$this->assertTrue($group->hasPermission('delete blog entries'));
$this->assertFalse($group->hasPermission('delete news entries'));
$this->assertFalse($group->hasPermission('view blog posts'));
}

#[Test]
public function it_checks_if_it_has_super_permissions()
{
Expand Down