Skip to content
Merged
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
4 changes: 1 addition & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ jobs:
strategy:
matrix:
version:
- 8.2
- 8.3
- 8.4
- 8.5
steps:
- uses: shivammathur/setup-php@v2
with:
Expand Down
16 changes: 8 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
"homepage": "https://www.alchemy.fr/",
"license": "MIT",
"require": {
"php": "^8.2",
"php": "^8.5",
"ext-json": "*",
"doctrine/orm": "^2.6",
"ramsey/uuid-doctrine": "^1.5",
"symfony/event-dispatcher": "^4.0|^5.4|^6.1",
"symfony/framework-bundle": "^4.0|^5.4|^6.1",
"symfony/security-bundle": "^4.0|^5.4|^6.1",
"symfony/validator": "^6.3",
"symfony/yaml": "^4.4|^5.4|^6.1"
"doctrine/orm": "^2.6|^3.6.1",
"ramsey/uuid-doctrine": "^1.5|^2.1.0",
"symfony/event-dispatcher": "^6.4|^7.4",
"symfony/framework-bundle": "^6.4|^7.4",
"symfony/security-bundle": "^6.4|^7.4",
"symfony/validator": "^6.4|^7.4",
"symfony/yaml": "6.4|^7.4"
},
"config": {
"sort-packages": true
Expand Down
1 change: 1 addition & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
->withPhpSets(
php84: true,
)
->withAttributesSets(all: true)
->withTypeCoverageLevel(0)
->withDeadCodeLevel(0)
->withCodeQualityLevel(0);
2 changes: 1 addition & 1 deletion src/Admin/PermissionView.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function getViewParameters(string $objectKey, ?string $id): array
'userId' => $ace->getUserId() ?? AccessControlEntryInterface::USER_WILDCARD,
'name' => $this->resolveUserName($ace),
'objectId' => $ace->getObjectId(),
'permissions' => array_map(fn (int $p): bool => $ace->hasPermission($p), $permissions),
'permissions' => array_map($ace->hasPermission(...), $permissions),
], $aces);

$objectTitle = null;
Expand Down
10 changes: 7 additions & 3 deletions src/Controller/PermissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@

class PermissionController extends AbstractController
{
public function __construct(private readonly PermissionManager $permissionManager, private readonly EntityManagerInterface $em, private readonly ObjectMapping $objectMapping)
public function __construct(
private readonly PermissionManager $permissionManager,
private readonly EntityManagerInterface $em,
private readonly ObjectMapping $objectMapping,
)
{
}

Expand Down Expand Up @@ -95,7 +99,7 @@ public function indexAces(

$aces = $repository->findAcesByParams($params);

return new JsonResponse(array_map(fn (AccessControlEntryInterface $ace): array => $aceSerializer->serialize($ace), $aces));
return new JsonResponse(array_map($aceSerializer->serialize(...), $aces));
}

#[Route(path: '/ace', name: 'ace_delete', methods: ['DELETE'])]
Expand All @@ -118,7 +122,7 @@ public function deleteAce(Request $request): Response

private function getRequestData(Request $request): array
{
if ('json' !== $request->getContentType() || empty($request->getContent())) {
if ('json' !== $request->getContentTypeFormat() || empty($request->getContent())) {
if ('GET' === $request->getMethod()) {
return $request->query->all();
}
Expand Down
58 changes: 20 additions & 38 deletions src/Entity/AccessControlEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,70 +9,52 @@
use Ramsey\Uuid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;

/**
* @ORM\Table(
* uniqueConstraints={@ORM\UniqueConstraint(name="uniq_ace", columns={"user_type", "user_id", "object_type", "object_id", "parent_id"})},
* indexes={
* @ORM\Index(name="user_idx", columns={"user_type", "user_id"}),
* @ORM\Index(name="object_idx", columns={"object_type", "object_id"}),
* @ORM\Index(name="user_type_idx", columns={"user_type"}),
* @ORM\Index(name="object_type_idx", columns={"object_type"}),
* @ORM\Index(name="parent_idx", columns={"parent_id"}),
* }
* )
* @ORM\Entity(repositoryClass="AccessControlEntryRepository")
*/
#[ORM\Entity(repositoryClass: AccessControlEntryRepository::class)]
#[ORM\Table]
#[ORM\Index(name: 'user_idx', columns: ['user_type', 'user_id'])]
#[ORM\Index(name: 'object_idx', columns: ['object_type', 'object_id'])]
#[ORM\Index(name: 'user_type_idx', columns: ['user_type'])]
#[ORM\Index(name: 'object_type_idx', columns: ['object_type'])]
#[ORM\Index(name: 'parent_idx', columns: ['parent_id'])]
#[ORM\UniqueConstraint(name: 'uniq_ace', columns: ['user_type', 'user_id', 'object_type', 'object_id', 'parent_id'])]
class AccessControlEntry implements AccessControlEntryInterface
{
/**
* @var Uuid
*
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
#[ORM\Id]
#[ORM\Column(type: 'uuid', unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: \Ramsey\Uuid\Doctrine\UuidGenerator::class)]
protected $id;

/**
* @ORM\Column(type="smallint")
*/
#[ORM\Column(type: 'smallint')]
protected int $userType = self::TYPE_USER_VALUE;

/**
* @ORM\Column(type="string", length=36, nullable=true)
*/
#[ORM\Column(type: 'string', length: 36, nullable: true)]
protected ?string $userId = null;

/**
* The object type name (i.e. publication).
*
* @ORM\Column(type="string", length=20)
*/
#[Assert\NotNull]
#[ORM\Column(type: 'string', length: 20)]
protected ?string $objectType = null;

/**
* @ORM\Column(type="uuid", nullable=true)
*/
#[ORM\Column(type: 'uuid', nullable: true)]
protected ?string $objectId = null;

/**
* @ORM\Column(type="integer")
*/
#[ORM\Column(type: 'integer')]
protected int $mask = 0;

/**
* i.e. "p:b9ccf60e-9f08-4388-b703-2953c40cb0a7".
*
* @ORM\Column(type="string", length=39, nullable=true)
*/
#[ORM\Column(type: 'string', length: 39, nullable: true)]
protected ?string $parentId = null;

/**
* @ORM\Column(type="datetime")
*/
private \DateTime $createdAt;
#[ORM\Column(type: 'datetime')]
private readonly \DateTime $createdAt;

public function __construct()
{
Expand Down
3 changes: 2 additions & 1 deletion src/Security/Voter/AclVoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Alchemy\AclBundle\Security\PermissionManager;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

#[AutoconfigureTag(name: 'security.voter')]
Expand All @@ -33,7 +34,7 @@ public function supportsType(string $subjectType): bool
return is_a($subjectType, AclObjectInterface::class, true);
}

protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
{
$user = $token->getUser();
if ($user instanceof AclUserInterface) {
Expand Down
2 changes: 1 addition & 1 deletion src/Security/Voter/SetPermissionVoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function supportsType(string $subjectType): bool
/**
* @param AclObjectInterface $subject
*/
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?\Symfony\Component\Security\Core\Authorization\Voter\Vote $vote = null): bool
{
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
Expand Down
9 changes: 3 additions & 6 deletions tests/PermissionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
use Alchemy\AclBundle\Security\PermissionManager;
use Alchemy\AclBundle\Tests\Mock\AclUserMock;
use Alchemy\AclBundle\Tests\Mock\ObjectMock;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class PermissionTest extends TestCase
{
/**
* @dataProvider permissionProvider
*/
#[DataProvider('permissionProvider')]
public function testPermissionsWithUser(array $acePermissions, int $permissionToTest, bool $expectedResult)
{
$ace = $this->createAce(AccessControlEntry::TYPE_USER_VALUE, '123', 'pub', '42', $acePermissions);
Expand Down Expand Up @@ -53,9 +52,7 @@ public function testPermissionsWithUser(array $acePermissions, int $permissionTo
$this->assertEquals($expectedResult, $permissionManager->isGranted($user, $object, $permissionToTest));
}

/**
* @dataProvider permissionProvider
*/
#[DataProvider('permissionProvider')]
public function testPermissionsWithGroup(array $acePermissions, int $permissionToTest, bool $expectedResult)
{
$userAce = $this->createAce(AccessControlEntry::TYPE_USER_VALUE, '123', 'pub', '42', []);
Expand Down