mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-03-02 20:19:43 +00:00
Fix issues with permission for stored objects associated with workflows
This commit is contained in:
@@ -15,7 +15,10 @@ use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowAttachment;
|
||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelperInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
@@ -34,7 +37,8 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
|
||||
|
||||
public function __construct(
|
||||
private readonly Security $security,
|
||||
private readonly ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
|
||||
private readonly EntityWorkflowAttachmentRepository $entityWorkflowAttachmentRepository,
|
||||
private readonly WorkflowRelatedEntityPermissionHelperInterface $workflowDocumentService,
|
||||
) {}
|
||||
|
||||
public function supports(StoredObjectRoleEnum $attribute, StoredObject $subject): bool
|
||||
@@ -46,16 +50,6 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
|
||||
|
||||
public function voteOnAttribute(StoredObjectRoleEnum $attribute, StoredObject $subject, TokenInterface $token): bool
|
||||
{
|
||||
// we first try to get the permission from the workflow, as attachement (this is the less intensive query)
|
||||
$workflowPermissionAsAttachment = match ($attribute) {
|
||||
StoredObjectRoleEnum::SEE => $this->workflowDocumentService->isAllowedByWorkflowForReadOperation($subject),
|
||||
StoredObjectRoleEnum::EDIT => $this->workflowDocumentService->isAllowedByWorkflowForWriteOperation($subject),
|
||||
};
|
||||
|
||||
if (WorkflowRelatedEntityPermissionHelper::FORCE_DENIED === $workflowPermissionAsAttachment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve the related entity
|
||||
$entity = $this->getRepository()->findAssociatedEntityToStoredObject($subject);
|
||||
|
||||
@@ -65,7 +59,7 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
|
||||
$regularPermission = $this->security->isGranted($voterAttribute, $entity);
|
||||
|
||||
if (!$this->canBeAssociatedWithWorkflow()) {
|
||||
return $regularPermission;
|
||||
return $this->voteOnStoredObjectAsAttachementOfAWorkflow($attribute, $regularPermission, $subject);
|
||||
}
|
||||
|
||||
$workflowPermission = match ($attribute) {
|
||||
@@ -74,9 +68,41 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
|
||||
};
|
||||
|
||||
return match ($workflowPermission) {
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT => true,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED => false,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN => WorkflowRelatedEntityPermissionHelper::FORCE_GRANT === $workflowPermissionAsAttachment || $regularPermission,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT => true,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED => false,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN => $this->voteOnStoredObjectAsAttachementOfAWorkflow($attribute, $regularPermission, $subject),
|
||||
};
|
||||
}
|
||||
|
||||
private function voteOnStoredObjectAsAttachementOfAWorkflow(StoredObjectRoleEnum $attribute, bool $regularPermission, StoredObject $storedObject): bool
|
||||
{
|
||||
$attachments = $this->entityWorkflowAttachmentRepository->findByStoredObject($storedObject);
|
||||
|
||||
// we get all the entity workflows where the stored object is attached
|
||||
$entityWorkflows = array_map(static fn (EntityWorkflowAttachment $attachment) => $attachment->getEntityWorkflow(), $attachments);
|
||||
|
||||
// we compute all the permission for each entity workflow
|
||||
$permissions = array_map(fn (EntityWorkflow $entityWorkflow): string => match ($attribute) {
|
||||
StoredObjectRoleEnum::SEE => $this->workflowDocumentService->isAllowedByWorkflowForReadOperation($entityWorkflow),
|
||||
StoredObjectRoleEnum::EDIT => $this->workflowDocumentService->isAllowedByWorkflowForWriteOperation($entityWorkflow),
|
||||
}, $entityWorkflows);
|
||||
|
||||
// now, we reduce the permissions: abstain are ignored. Between DENIED and and GRANT, DENIED takes precedence
|
||||
$computedPermission = WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN;
|
||||
foreach ($permissions as $permission) {
|
||||
if (WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED === $permission) {
|
||||
return false;
|
||||
}
|
||||
if (WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT === $permission) {
|
||||
$computedPermission = WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT;
|
||||
}
|
||||
}
|
||||
|
||||
if (WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN === $computedPermission) {
|
||||
return $regularPermission;
|
||||
}
|
||||
|
||||
// this is the case where WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT is returned
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
|
||||
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
|
||||
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
@@ -25,8 +26,9 @@ final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredOb
|
||||
private readonly AccompanyingCourseDocumentRepository $repository,
|
||||
Security $security,
|
||||
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
|
||||
EntityWorkflowAttachmentRepository $attachmentRepository,
|
||||
) {
|
||||
parent::__construct($security, $workflowDocumentService);
|
||||
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
|
||||
}
|
||||
|
||||
protected function getRepository(): AssociatedEntityToStoredObjectInterface
|
||||
|
||||
@@ -16,6 +16,7 @@ use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
|
||||
use Chill\DocStoreBundle\Repository\PersonDocumentRepository;
|
||||
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
@@ -25,8 +26,9 @@ class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter
|
||||
private readonly PersonDocumentRepository $repository,
|
||||
Security $security,
|
||||
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
|
||||
EntityWorkflowAttachmentRepository $attachmentRepository,
|
||||
) {
|
||||
parent::__construct($security, $workflowDocumentService);
|
||||
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
|
||||
}
|
||||
|
||||
protected function getRepository(): AssociatedEntityToStoredObjectInterface
|
||||
|
||||
@@ -16,8 +16,11 @@ use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
|
||||
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowAttachment;
|
||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
|
||||
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelperInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
@@ -31,21 +34,31 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
/**
|
||||
* @param array<int, EntityWorkflowAttachment> $attachments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function buildStoredObjectVoter(
|
||||
bool $canBeAssociatedWithWorkflow,
|
||||
AssociatedEntityToStoredObjectInterface $repository,
|
||||
Security $security,
|
||||
?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
|
||||
?WorkflowRelatedEntityPermissionHelperInterface $workflowDocumentService = null,
|
||||
array $attachments = [],
|
||||
): AbstractStoredObjectVoter {
|
||||
$attachmentsRepository = $this->prophesize(EntityWorkflowAttachmentRepository::class);
|
||||
$attachmentsRepository->findByStoredObject(Argument::type(StoredObject::class))->willReturn($attachments);
|
||||
|
||||
// Anonymous class extending the abstract class
|
||||
return new class ($canBeAssociatedWithWorkflow, $repository, $security, $workflowDocumentService) extends AbstractStoredObjectVoter {
|
||||
return new class ($canBeAssociatedWithWorkflow, $repository, $security, $attachmentsRepository->reveal(), $workflowDocumentService) extends AbstractStoredObjectVoter {
|
||||
public function __construct(
|
||||
private readonly bool $canBeAssociatedWithWorkflow,
|
||||
private readonly AssociatedEntityToStoredObjectInterface $repository,
|
||||
Security $security,
|
||||
?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
|
||||
EntityWorkflowAttachmentRepository $attachmentRepository,
|
||||
WorkflowRelatedEntityPermissionHelperInterface $workflowDocumentService,
|
||||
) {
|
||||
parent::__construct($security, $workflowDocumentService);
|
||||
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
|
||||
}
|
||||
|
||||
protected function attributeToRole($attribute): string
|
||||
@@ -72,28 +85,29 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
|
||||
public function testSupportsOnAttribute(): void
|
||||
{
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(new \stdClass()), $this->prophesize(Security::class)->reveal(), null);
|
||||
$entityWorkflowService = $this->prophesize(WorkflowRelatedEntityPermissionHelperInterface::class);
|
||||
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(new \stdClass()), $this->prophesize(Security::class)->reveal(), $entityWorkflowService->reveal());
|
||||
|
||||
self::assertTrue($voter->supports(StoredObjectRoleEnum::SEE, new StoredObject()));
|
||||
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(new User()), $this->prophesize(Security::class)->reveal(), null);
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(new User()), $this->prophesize(Security::class)->reveal(), $entityWorkflowService->reveal());
|
||||
|
||||
self::assertFalse($voter->supports(StoredObjectRoleEnum::SEE, new StoredObject()));
|
||||
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(null), $this->prophesize(Security::class)->reveal(), null);
|
||||
$voter = $this->buildStoredObjectVoter(false, new DummyRepository(null), $this->prophesize(Security::class)->reveal(), $entityWorkflowService->reveal());
|
||||
|
||||
self::assertFalse($voter->supports(StoredObjectRoleEnum::SEE, new StoredObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProviderVoteOnAttributeWithStoredObjectPermission
|
||||
* @dataProvider dataProviderVoteOnAttributeWithWorkflow
|
||||
*/
|
||||
public function testVoteOnAttributeWithStoredObjectPermission(
|
||||
public function testVoteOnAttributeWithWorkflow(
|
||||
StoredObjectRoleEnum $attribute,
|
||||
bool $expected,
|
||||
bool $isGrantedRegularPermission,
|
||||
string $isGrantedWorkflowPermission,
|
||||
string $isGrantedStoredObjectAttachment,
|
||||
): void {
|
||||
$storedObject = new StoredObject();
|
||||
$repository = new DummyRepository($related = new \stdClass());
|
||||
@@ -102,31 +116,28 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted('SOME_ROLE', $related)->willReturn($isGrantedRegularPermission);
|
||||
|
||||
$workflowRelatedEntityPermissionHelper = $this->prophesize(WorkflowRelatedEntityPermissionHelper::class);
|
||||
$workflowRelatedEntityPermissionHelper = $this->prophesize(WorkflowRelatedEntityPermissionHelperInterface::class);
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted('SOME_ROLE', $related)->willReturn($isGrantedRegularPermission);
|
||||
|
||||
$attachementRepository = $this->prophesize(EntityWorkflowAttachmentRepository::class);
|
||||
$attachementRepository->findByStoredObject($storedObject)->willReturn([]);
|
||||
|
||||
if (StoredObjectRoleEnum::SEE === $attribute) {
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForReadOperation($storedObject)
|
||||
->shouldBeCalled()
|
||||
->willReturn($isGrantedStoredObjectAttachment);
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForReadOperation($related)
|
||||
->willReturn($isGrantedWorkflowPermission);
|
||||
} elseif (StoredObjectRoleEnum::EDIT === $attribute) {
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForWriteOperation($storedObject)
|
||||
->shouldBeCalled()
|
||||
->willReturn($isGrantedStoredObjectAttachment);
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForWriteOperation($related)
|
||||
->willReturn($isGrantedWorkflowPermission);
|
||||
} else {
|
||||
throw new \LogicException('Invalid attribute for StoredObjectVoter');
|
||||
}
|
||||
|
||||
$storedObjectVoter = new class ($repository, $workflowRelatedEntityPermissionHelper->reveal(), $security->reveal()) extends AbstractStoredObjectVoter {
|
||||
public function __construct(private $repository, $helper, $security)
|
||||
$storedObjectVoter = new class ($repository, $workflowRelatedEntityPermissionHelper->reveal(), $security->reveal(), $attachementRepository->reveal()) extends AbstractStoredObjectVoter {
|
||||
public function __construct(private $repository, $helper, $security, EntityWorkflowAttachmentRepository $attachmentRepository)
|
||||
{
|
||||
parent::__construct($security, $helper);
|
||||
parent::__construct($security, $attachmentRepository, $helper);
|
||||
}
|
||||
|
||||
protected function getRepository(): AssociatedEntityToStoredObjectInterface
|
||||
@@ -155,96 +166,64 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
self::assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public static function dataProviderVoteOnAttributeWithStoredObjectPermission(): iterable
|
||||
public static function dataProviderVoteOnAttributeWithWorkflow(): iterable
|
||||
{
|
||||
foreach (['read' => StoredObjectRoleEnum::SEE, 'write' => StoredObjectRoleEnum::EDIT] as $action => $attribute) {
|
||||
yield 'Not related to any workflow nor attachment ('.$action.')' => [
|
||||
$attribute,
|
||||
true,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
];
|
||||
|
||||
yield 'Not related to any workflow nor attachment (refuse) ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
false,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (workflow) ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (stored object) ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (workflow) although grant ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (stored object) although grant ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
true,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (initially refused) (workflow) although grant ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
false,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
];
|
||||
|
||||
yield 'Is granted by a workflow takes precedence (initially refused) (stored object) although grant ('.$action.')' => [
|
||||
$attribute,
|
||||
false,
|
||||
false,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED,
|
||||
];
|
||||
|
||||
yield 'Force grant inverse the regular permission (workflow) ('.$action.')' => [
|
||||
$attribute,
|
||||
true,
|
||||
false,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
];
|
||||
|
||||
yield 'Force grant inverse the regular permission (so) ('.$action.')' => [
|
||||
$attribute,
|
||||
true,
|
||||
false,
|
||||
WorkflowRelatedEntityPermissionHelper::ABSTAIN,
|
||||
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT,
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProviderVoteOnAttributeWithoutStoredObjectPermission
|
||||
* @dataProvider dataProviderVoteOnAttribute
|
||||
*/
|
||||
public function testVoteOnAttributeWithoutStoredObjectPermission(
|
||||
public function testVoteOnAttribute(
|
||||
StoredObjectRoleEnum $attribute,
|
||||
bool $expected,
|
||||
bool $canBeAssociatedWithWorkflow,
|
||||
@@ -260,10 +239,7 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted('SOME_ROLE', $related)->willReturn($isGrantedRegularPermission);
|
||||
|
||||
$workflowRelatedEntityPermissionHelper = $this->prophesize(WorkflowRelatedEntityPermissionHelper::class);
|
||||
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForReadOperation($storedObject)->willReturn(WorkflowRelatedEntityPermissionHelper::ABSTAIN);
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForWriteOperation($storedObject)->willReturn(WorkflowRelatedEntityPermissionHelper::ABSTAIN);
|
||||
$workflowRelatedEntityPermissionHelper = $this->prophesize(WorkflowRelatedEntityPermissionHelperInterface::class);
|
||||
|
||||
if (null !== $isGrantedWorkflowPermissionRead) {
|
||||
$workflowRelatedEntityPermissionHelper->isAllowedByWorkflowForReadOperation($related)
|
||||
@@ -283,27 +259,155 @@ class AbstractStoredObjectVoterTest extends TestCase
|
||||
self::assertEquals($expected, $voter->voteOnAttribute($attribute, $storedObject, $token), $message);
|
||||
}
|
||||
|
||||
public static function dataProviderVoteOnAttributeWithoutStoredObjectPermission(): iterable
|
||||
public static function dataProviderVoteOnAttribute(): iterable
|
||||
{
|
||||
// not associated on a workflow
|
||||
yield [StoredObjectRoleEnum::SEE, true, false, true, null, null, 'not associated on a workflow, granted by regular access, must not rely on helper'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, false, false, null, null, 'not associated on a workflow, denied by regular access, must not rely on helper'];
|
||||
|
||||
// associated on a workflow, read operation
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, true, WorkflowRelatedEntityPermissionHelper::FORCE_GRANT, null, 'associated on a workflow, read by regular, force grant by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, true, WorkflowRelatedEntityPermissionHelper::ABSTAIN, null, 'associated on a workflow, read by regular, abstain by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, true, WorkflowRelatedEntityPermissionHelper::FORCE_DENIED, null, 'associated on a workflow, read by regular, force grant by workflow, ask for read, should be denied'];
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, false, WorkflowRelatedEntityPermissionHelper::FORCE_GRANT, null, 'associated on a workflow, denied read by regular, force grant by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, false, WorkflowRelatedEntityPermissionHelper::ABSTAIN, null, 'associated on a workflow, denied read by regular, abstain by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, false, WorkflowRelatedEntityPermissionHelper::FORCE_DENIED, null, 'associated on a workflow, denied read by regular, force grant by workflow, ask for read, should be denied'];
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, true, WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT, null, 'associated on a workflow, read by regular, force grant by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, true, WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN, null, 'associated on a workflow, read by regular, abstain by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, true, WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED, null, 'associated on a workflow, read by regular, force grant by workflow, ask for read, should be denied'];
|
||||
yield [StoredObjectRoleEnum::SEE, true, true, false, WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT, null, 'associated on a workflow, denied read by regular, force grant by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, false, WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN, null, 'associated on a workflow, denied read by regular, abstain by workflow, ask for read, should be granted'];
|
||||
yield [StoredObjectRoleEnum::SEE, false, true, false, WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED, null, 'associated on a workflow, denied read by regular, force grant by workflow, ask for read, should be denied'];
|
||||
|
||||
// association on a workflow, write operation
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, true, null, WorkflowRelatedEntityPermissionHelper::FORCE_GRANT, 'associated on a workflow, write by regular, force grant by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, true, null, WorkflowRelatedEntityPermissionHelper::ABSTAIN, 'associated on a workflow, write by regular, abstain by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, true, null, WorkflowRelatedEntityPermissionHelper::FORCE_DENIED, 'associated on a workflow, write by regular, force grant by workflow, ask for write, should be denied'];
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, false, null, WorkflowRelatedEntityPermissionHelper::FORCE_GRANT, 'associated on a workflow, denied write by regular, force grant by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, false, null, WorkflowRelatedEntityPermissionHelper::ABSTAIN, 'associated on a workflow, denied write by regular, abstain by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, false, null, WorkflowRelatedEntityPermissionHelper::FORCE_DENIED, 'associated on a workflow, denied write by regular, force grant by workflow, ask for write, should be denied'];
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, true, null, WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT, 'associated on a workflow, write by regular, force grant by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, true, null, WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN, 'associated on a workflow, write by regular, abstain by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, true, null, WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED, 'associated on a workflow, write by regular, force grant by workflow, ask for write, should be denied'];
|
||||
yield [StoredObjectRoleEnum::EDIT, true, true, false, null, WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT, 'associated on a workflow, denied write by regular, force grant by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, false, null, WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN, 'associated on a workflow, denied write by regular, abstain by workflow, ask for write, should be granted'];
|
||||
yield [StoredObjectRoleEnum::EDIT, false, true, false, null, WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED, 'associated on a workflow, denied write by regular, force grant by workflow, ask for write, should be denied'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProviderPrecedenceOfDirectAssociationOverWorkflowAttachments
|
||||
*/
|
||||
public function testPrecedenceOfDirectAssociationOverWorkflowAttachments(
|
||||
StoredObjectRoleEnum $attribute,
|
||||
bool $expected,
|
||||
bool $regularPermission,
|
||||
string $directWorkflowPermission,
|
||||
string $attachmentWorkflowPermission,
|
||||
string $message,
|
||||
): void {
|
||||
$storedObject = new StoredObject();
|
||||
$repository = new DummyRepository($related = new \stdClass());
|
||||
$token = new UsernamePasswordToken(new User(), 'dummy');
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->isGranted('SOME_ROLE', $related)->willReturn($regularPermission);
|
||||
|
||||
$workflowHelper = $this->prophesize(WorkflowRelatedEntityPermissionHelperInterface::class);
|
||||
|
||||
// Direct association permission
|
||||
if (StoredObjectRoleEnum::SEE === $attribute) {
|
||||
$workflowHelper->isAllowedByWorkflowForReadOperation($related)
|
||||
->willReturn($directWorkflowPermission);
|
||||
} else {
|
||||
$workflowHelper->isAllowedByWorkflowForWriteOperation($related)
|
||||
->willReturn($directWorkflowPermission);
|
||||
}
|
||||
|
||||
// Attachment permission
|
||||
$entityWorkflow = $this->prophesize(\Chill\MainBundle\Entity\Workflow\EntityWorkflow::class)->reveal();
|
||||
$attachment = $this->prophesize(EntityWorkflowAttachment::class);
|
||||
$attachment->getEntityWorkflow()->willReturn($entityWorkflow);
|
||||
|
||||
if (StoredObjectRoleEnum::SEE === $attribute) {
|
||||
$workflowHelper->isAllowedByWorkflowForReadOperation($entityWorkflow)
|
||||
->willReturn($attachmentWorkflowPermission);
|
||||
} else {
|
||||
$workflowHelper->isAllowedByWorkflowForWriteOperation($entityWorkflow)
|
||||
->willReturn($attachmentWorkflowPermission);
|
||||
}
|
||||
|
||||
$voter = $this->buildStoredObjectVoter(
|
||||
true,
|
||||
$repository,
|
||||
$security->reveal(),
|
||||
$workflowHelper->reveal(),
|
||||
[$attachment->reveal()]
|
||||
);
|
||||
|
||||
self::assertEquals($expected, $voter->voteOnAttribute($attribute, $storedObject, $token), $message);
|
||||
}
|
||||
|
||||
public static function dataProviderPrecedenceOfDirectAssociationOverWorkflowAttachments(): iterable
|
||||
{
|
||||
$cases = [
|
||||
[
|
||||
'expected' => true,
|
||||
'regular' => false,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
'message' => 'Direct FORCE_GRANT should win over attachment FORCE_DENIED',
|
||||
],
|
||||
[
|
||||
'expected' => false,
|
||||
'regular' => true,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
'message' => 'Direct FORCE_DENIED should win over attachment FORCE_GRANT',
|
||||
],
|
||||
[
|
||||
'expected' => true,
|
||||
'regular' => false,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'message' => 'Direct FORCE_GRANT should win over attachment ABSTAIN',
|
||||
],
|
||||
[
|
||||
'expected' => false,
|
||||
'regular' => true,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'message' => 'Direct FORCE_DENIED should win over attachment ABSTAIN',
|
||||
],
|
||||
[
|
||||
'expected' => true,
|
||||
'regular' => false,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT,
|
||||
'message' => 'Direct ABSTAIN should let attachment FORCE_GRANT win',
|
||||
],
|
||||
[
|
||||
'expected' => false,
|
||||
'regular' => true,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED,
|
||||
'message' => 'Direct ABSTAIN should let attachment FORCE_DENIED win',
|
||||
],
|
||||
[
|
||||
'expected' => true,
|
||||
'regular' => true,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'message' => 'Both ABSTAIN should let regular permission (true) win',
|
||||
],
|
||||
[
|
||||
'expected' => false,
|
||||
'regular' => false,
|
||||
'direct' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'attachment' => WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN,
|
||||
'message' => 'Both ABSTAIN should let regular permission (false) win',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ([StoredObjectRoleEnum::SEE, StoredObjectRoleEnum::EDIT] as $attribute) {
|
||||
foreach ($cases as $case) {
|
||||
yield sprintf('%s - %s', $attribute->name, $case['message']) => [
|
||||
$attribute,
|
||||
$case['expected'],
|
||||
$case['regular'],
|
||||
$case['direct'],
|
||||
$case['attachment'],
|
||||
$case['message'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user