Skip to content

Commit

Permalink
feat: Added security layer on NodesSources form type for each node-ty…
Browse files Browse the repository at this point in the history
…pe-field (NodeTypeFieldVoter)
  • Loading branch information
ambroisemaupate committed Jun 13, 2024
1 parent 899b397 commit 29b0332
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Security\Authorization\Voter;

use RZ\Roadiz\CoreBundle\Entity\NodeTypeField;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;

final class NodeTypeFieldVoter extends Voter
{
public const VIEW = 'VIEW';

public function __construct(
private readonly Security $security
) {
}

protected function supports(string $attribute, mixed $subject): bool
{
if (!\in_array($attribute, [self::VIEW])) {
return false;
}
return $subject instanceof NodeTypeField;
}

protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();

if (!$user instanceof UserInterface) {
// the user must be logged in; if not, deny access
return false;
}

return match ($attribute) {
self::VIEW => $this->canView($subject, $user),
default => throw new \LogicException('This code should not be reached!')
};
}

private function canView(NodeTypeField $field, UserInterface $user): bool
{
if ($field->isNodes() && !$this->security->isGranted(NodeVoter::SEARCH)) {
return false;
}
if ($field->isDocuments() && !$this->security->isGranted('ROLE_ACCESS_DOCUMENTS')) {
return false;
}
if ($field->isUser() && !$this->security->isGranted('ROLE_ACCESS_USERS')) {
return false;
}
if ($field->isCustomForms() && !$this->security->isGranted('ROLE_ACCESS_CUSTOMFORMS')) {
return false;
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,12 @@ private function canReadAtRoot(UserInterface $user): bool
return null === $chroot && $this->security->isGranted('ROLE_ACCESS_NODES');
}

/*
* All node users can search even if they are chroot-ed
*/
private function canSearch(UserInterface $user): bool
{
$chroot = $this->chrootResolver->getChroot($user);
return null === $chroot && $this->security->isGranted('ROLE_ACCESS_NODES');
return $this->security->isGranted('ROLE_ACCESS_NODES');
}

private function canEmptyTrash(UserInterface $user): bool
Expand Down
21 changes: 13 additions & 8 deletions lib/Rozier/src/Forms/NodeSource/NodeSourceType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use RZ\Roadiz\CoreBundle\Form\MarkdownType;
use RZ\Roadiz\CoreBundle\Form\MultipleEnumerationType;
use RZ\Roadiz\CoreBundle\Form\YamlType;
use RZ\Roadiz\CoreBundle\Security\Authorization\Voter\NodeTypeFieldVoter;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
Expand All @@ -40,18 +42,18 @@
final class NodeSourceType extends AbstractType
{
protected ManagerRegistry $managerRegistry;
private Security $security;

/**
* @param ManagerRegistry $managerRegistry
*/
public function __construct(ManagerRegistry $managerRegistry)
public function __construct(ManagerRegistry $managerRegistry, Security $security)
{
$this->managerRegistry = $managerRegistry;
$this->security = $security;
}

/**
* @param FormBuilderInterface $builder
* @param array $options
* @param FormBuilderInterface $builder
* @param array $options
* @throws \ReflectionException
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
Expand All @@ -63,8 +65,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'translation' => $builder->getData()->getTranslation(),
]);
}
/** @var NodeTypeField $field */

foreach ($fields as $field) {
if (!$this->security->isGranted(NodeTypeFieldVoter::VIEW, $field)) {
continue;
}
if ($options['withVirtual'] === true || !$field->isVirtual()) {
$builder->add(
$field->getVarName(),
Expand Down Expand Up @@ -106,7 +111,7 @@ public function getBlockPrefix(): string
/**
* @param NodesSources $source
* @param NodeType $nodeType
* @return array
* @return array<NodeTypeField>
*/
private function getFieldsForSource(NodesSources $source, NodeType $nodeType): array
{
Expand Down

0 comments on commit 29b0332

Please sign in to comment.