Skip to content

Commit

Permalink
Merge pull request #1953 from tomudding/feature/improved-custom-page-…
Browse files Browse the repository at this point in the history
…authorization-checks

feat: dynamically evaluate page access permissions
  • Loading branch information
tomudding authored Dec 29, 2024
2 parents 43c1cfb + 5d63c8b commit b452472
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 67 deletions.
2 changes: 1 addition & 1 deletion module/Frontpage/src/Model/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,6 @@ public function toArray(): array
*/
public function getResourceId(): string
{
return 'page' . $this->getId();
return 'page';
}
}
26 changes: 1 addition & 25 deletions module/Frontpage/src/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@
use Frontpage\Service\Page as PageService;
use Frontpage\Service\Poll as PollService;
use Psr\Container\ContainerInterface;
use RuntimeException;
use User\Authorization\AclServiceFactory;

use function sprintf;

class Module
{
/**
Expand All @@ -58,28 +55,7 @@ public function getServiceConfig(): array
return [
'factories' => [
// Services
AclService::class => static function (
ContainerInterface $container,
$requestedName,
?array $options = null,
) {
$aclService = (new AclServiceFactory())->__invoke($container, $requestedName, $options);

if ($aclService instanceof AclService) {
$pages = $container->get(PageMapper::class)->findAll();
$aclService->setPages($pages);

return $aclService;
}

throw new RuntimeException(
sprintf(
'Expected service of type %s, got service of type %s',
AclService::class,
$aclService::class,
),
);
},
AclService::class => AclServiceFactory::class,
FrontpageService::class => FrontpageServiceFactory::class,
NewsService::class => NewsServiceFactory::class,
PageService::class => PageServiceFactory::class,
Expand Down
16 changes: 3 additions & 13 deletions module/Frontpage/src/Service/AclService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,11 @@

namespace Frontpage\Service;

use Frontpage\Model\Page as PageModel;
use Laminas\Permissions\Acl\Resource\GenericResource as Resource;
use User\Permissions\Assertion\IsAllowedToViewPage;

class AclService extends \User\Service\AclService
{
/**
* @param PageModel[] $pages
*/
public function setPages(array $pages): void
{
foreach ($pages as $page) {
$requiredRole = $page->getRequiredRole()->value;
$this->acl->addResource($page);
$this->acl->allow($requiredRole, $page, 'view');
}
}

protected function createAcl(): void
{
parent::createAcl();
Expand All @@ -36,5 +24,7 @@ protected function createAcl(): void
$this->acl->allow('user', 'infimum', 'view');
$this->acl->allow('user', 'poll', ['vote', 'request']);
$this->acl->allow('user', 'poll_comment', ['view', 'create', 'list']);

$this->acl->allow(null, 'page', 'view', new IsAllowedToViewPage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@
class IsAfterMembershipEndedAndNotTagged implements AssertionInterface
{
/**
* Returns true if and only if the assertion conditions are met.
*
* This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
* $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
* privileges, respectively.
*
* @param string|null $privilege
* @inheritDoc
*/
public function assert(
Acl $acl,
Expand Down
35 changes: 35 additions & 0 deletions module/User/src/Permissions/Assertion/IsAllowedToViewPage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace User\Permissions\Assertion;

use Frontpage\Model\Page as PageModel;
use Laminas\Permissions\Acl\Acl;
use Laminas\Permissions\Acl\Assertion\AssertionInterface;
use Laminas\Permissions\Acl\Resource\ResourceInterface;
use Laminas\Permissions\Acl\Role\RoleInterface;

/**
* Assertion to check if whoever is trying to view the page is allowed to view the page.
*/
class IsAllowedToViewPage implements AssertionInterface
{
/**
* @inheritDoc
*/
public function assert(
Acl $acl,
?RoleInterface $role = null,
?ResourceInterface $resource = null,
$privilege = null,
): bool {
if (!$resource instanceof PageModel) {
return false;
}

$requiredRole = $resource->getRequiredRole()->value;

return $role->getRoleId() === $requiredRole || $acl->inheritsRole($role, $requiredRole);
}
}
8 changes: 1 addition & 7 deletions module/User/src/Permissions/Assertion/IsCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@
class IsCreator implements AssertionInterface
{
/**
* Returns true if and only if the assertion conditions are met.
*
* This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
* $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
* privileges, respectively.
*
* @param string|null $privilege
* @inheritDoc
*/
public function assert(
Acl $acl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@
class IsCreatorOrOrganMember implements AssertionInterface
{
/**
* Returns true if and only if the assertion conditions are met.
*
* This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
* $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
* privileges, respectively.
*
* @param string|null $privilege
* @inheritDoc
*/
public function assert(
Acl $acl,
Expand Down
8 changes: 1 addition & 7 deletions module/User/src/Permissions/Assertion/IsOrganMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@
class IsOrganMember implements AssertionInterface
{
/**
* Returns true if and only if the assertion conditions are met.
*
* This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
* $role, $resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
* privileges, respectively.
*
* @param string|null $privilege
* @inheritDoc
*/
public function assert(
Acl $acl,
Expand Down
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
<exclude-pattern>module/User/src/Service/Factory/UserFactory.php</exclude-pattern>
<!-- Permission assertions -->
<exclude-pattern>module/User/src/Permissions/Assertion/IsAfterMembershipEndedAndNotTagged.php</exclude-pattern>
<exclude-pattern>module/User/src/Permissions/Assertion/IsAllowedToViewPage.php</exclude-pattern>
<exclude-pattern>module/User/src/Permissions/Assertion/IsCreator.php</exclude-pattern>
<exclude-pattern>module/User/src/Permissions/Assertion/IsCreatorOrOrganMember.php</exclude-pattern>
<exclude-pattern>module/User/src/Permissions/Assertion/IsOrganMember.php</exclude-pattern>
Expand Down

0 comments on commit b452472

Please sign in to comment.