Auth: Added canAny

This commit is contained in:
Igor Scheller 2024-04-07 14:18:38 +02:00 committed by xuwhite
parent d18e203560
commit a214e0ff8f
8 changed files with 80 additions and 31 deletions

View File

@ -677,11 +677,7 @@ function User_view(
url('/shifts-json-export', ['key' => $user_source->api_key]),
icon('braces') . __('JSON Export')
) : '',
(
$auth->can('shifts_json_export')
|| $auth->can('ical')
|| $auth->can('atom')
) ? button(
$auth->canAny(['shifts_json_export', 'ical', 'atom']) ? button(
url('/user-myshifts', ['reset' => 1]),
icon('arrow-repeat') . __('Reset API key')
) : '',

View File

@ -38,8 +38,7 @@ class UserSettingsController extends BaseController
if (
!(
$this->auth->can('user.ifsg.edit')
|| $this->auth->can('user.drive.edit')
$this->auth->canAny(['user.ifsg.edit', 'user.drive.edit'])
|| $this->isDriverLicenseSupporter()
|| $this->isIfsgSupporter()
)
@ -158,9 +157,8 @@ class UserSettingsController extends BaseController
'title' => 'settings.certificates',
'icon' => 'card-checklist',
'permission' => (
$this->auth->can('user.ifsg.edit')
$this->auth->canAny(['user.ifsg.edit', 'user.drive.edit'])
|| $this->isIfsgSupporter()
|| $this->auth->can('user.drive.edit')
|| $this->isDriverLicenseSupporter()
) ? null : '_',
];

View File

@ -102,8 +102,7 @@ class NewsController extends BaseController
$comment = $this->comment->findOrFail($commentId);
if (
$comment->user->id != $this->auth->user()->id
&& !$this->auth->can('admin_news')
&& !$this->auth->can('comment.delete')
&& !$this->auth->canAny(['admin_news', 'comment.delete'])
) {
throw new HttpForbidden();
}

View File

@ -97,24 +97,7 @@ class Authenticator
$abilities = (array) $abilities;
if (empty($this->permissions)) {
$user = $this->user();
if ($user) {
$this->permissions = $user->privileges->pluck('name')->toArray();
if ($user->last_login_at < Carbon::now()->subMinutes(5) && !$this->isApiRequest()) {
$user->last_login_at = Carbon::now();
$user->save(['touch' => false]);
}
} elseif ($this->session->get('user_id')) {
$this->session->remove('user_id');
}
if (empty($this->permissions)) {
/** @var Group $group */
$group = Group::find($this->guestRole);
$this->permissions = $group->privileges->pluck('name')->toArray();
}
$this->loadPermissions();
}
foreach ($abilities as $ability) {
@ -126,6 +109,22 @@ class Authenticator
return true;
}
/**
* @param string[]|string $abilities
*/
public function canAny(array|string $abilities): bool
{
$abilities = (array) $abilities;
foreach ($abilities as $ability) {
if ($this->can($ability)) {
return true;
}
}
return false;
}
public function authenticate(string $login, string $password): ?User
{
/** @var User $user */
@ -248,4 +247,26 @@ class Authenticator
{
$this->guestRole = $guestRole;
}
protected function loadPermissions(): void
{
$user = $this->user();
if ($user) {
$this->permissions = $user->privileges->pluck('name')->toArray();
if ($user->last_login_at < Carbon::now()->subMinutes(5) && !$this->isApiRequest()) {
$user->last_login_at = Carbon::now();
$user->save(['touch' => false]);
}
} elseif ($this->session->get('user_id')) {
$this->session->remove('user_id');
}
if (empty($this->permissions)) {
/** @var Group $group */
$group = Group::find($this->guestRole);
$this->permissions = $group->privileges->pluck('name')->toArray();
}
}
}

View File

@ -23,6 +23,7 @@ class Authentication extends TwigExtension
new TwigFunction('is_user', [$this, 'isAuthenticated']),
new TwigFunction('is_guest', [$this, 'isGuest']),
new TwigFunction('has_permission_to', [$this->auth, 'can']),
new TwigFunction('has_permission_to_any', [$this->auth, 'canAny']),
];
}

View File

@ -64,7 +64,7 @@ class UserSettingsControllerTest extends ControllerTest
public function testCertificateByPermission(): void
{
config(['ifsg_enabled' => true]);
$this->setExpects($this->auth, 'can', ['user.ifsg.edit'], true, $this->atLeastOnce());
$this->setExpects($this->auth, 'canAny', [['user.ifsg.edit', 'user.drive.edit']], true, $this->atLeastOnce());
$this->response->expects($this->once())
->method('withView')

View File

@ -227,6 +227,7 @@ class AuthenticatorTest extends ServiceProviderTest
/**
* @covers \Engelsystem\Helpers\Authenticator::can
* @covers \Engelsystem\Helpers\Authenticator::loadPermissions
* @covers \Engelsystem\Helpers\Authenticator::isApiRequest
*/
public function testCan(): void
@ -252,11 +253,15 @@ class AuthenticatorTest extends ServiceProviderTest
$this->assertTrue($auth->can('bar'));
// Permissions cached
$this->assertTrue($auth->can('bar'));
$this->assertTrue($auth->can(['bar']));
// Can not
$this->assertFalse($auth->can(['nope']));
}
/**
* @covers \Engelsystem\Helpers\Authenticator::can
* @covers \Engelsystem\Helpers\Authenticator::loadPermissions
*/
public function testCanUnauthorized(): void
{
@ -275,6 +280,34 @@ class AuthenticatorTest extends ServiceProviderTest
$this->assertNull($session->get('user_id'));
}
/**
* @covers \Engelsystem\Helpers\Authenticator::canAny
*/
public function testCanAny(): void
{
$this->initDatabase();
$request = new Request();
$this->app->instance('request', $request);
$session = new Session(new MockArraySessionStorage());
/** @var User $user */
$user = User::factory()->create();
/** @var Group $group */
$group = Group::factory()->create();
/** @var Privilege $privilege */
$privilege = Privilege::factory()->create(['name' => 'bar']);
$user->groups()->attach($group);
$group->privileges()->attach($privilege);
$auth = new Authenticator($request, $session, new User());
$session->set('user_id', $user->id);
$this->assertTrue($auth->canAny('bar'));
$this->assertTrue($auth->canAny(['foo', 'bar', 'baz']));
$this->assertFalse($auth->canAny(['lorem', 'ipsum']));
}
/**
* @covers \Engelsystem\Helpers\Authenticator::authenticate
*/

View File

@ -26,6 +26,7 @@ class AuthenticationTest extends ExtensionTest
$this->assertExtensionExists('is_user', [$extension, 'isAuthenticated'], $functions);
$this->assertExtensionExists('is_guest', [$extension, 'isGuest'], $functions);
$this->assertExtensionExists('has_permission_to', [$auth, 'can'], $functions);
$this->assertExtensionExists('has_permission_to_any', [$auth, 'canAny'], $functions);
}
/**