diff --git a/app/config/security.yml b/app/config/security.yml index 76f10db70..b05e54b01 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -76,5 +76,4 @@ security: - { path: ^/settings, roles: ROLE_SUPER_ADMIN } - { path: ^/annotations, roles: ROLE_USER } - { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS } - - { path: ^/ignore-origin-instance-rules, roles: ROLE_SUPER_ADMIN } - { path: ^/, roles: ROLE_USER } diff --git a/src/Controller/IgnoreOriginInstanceRuleController.php b/src/Controller/IgnoreOriginInstanceRuleController.php index 6edc31fa2..5d8652c28 100644 --- a/src/Controller/IgnoreOriginInstanceRuleController.php +++ b/src/Controller/IgnoreOriginInstanceRuleController.php @@ -3,6 +3,7 @@ namespace Wallabag\Controller; use Doctrine\ORM\EntityManagerInterface; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -34,6 +35,7 @@ class IgnoreOriginInstanceRuleController extends AbstractController * Lists all IgnoreOriginInstanceRule entities. * * @Route("/", name="ignore_origin_instance_rules_index", methods={"GET"}) + * @IsGranted("LIST_IGNORE_ORIGIN_INSTANCE_RULES") */ public function indexAction(IgnoreOriginInstanceRuleRepository $repository) { @@ -48,6 +50,7 @@ class IgnoreOriginInstanceRuleController extends AbstractController * Creates a new ignore origin instance rule entity. * * @Route("/new", name="ignore_origin_instance_rules_new", methods={"GET", "POST"}) + * @IsGranted("CREATE_IGNORE_ORIGIN_INSTANCE_RULES") * * @return Response */ @@ -80,6 +83,7 @@ class IgnoreOriginInstanceRuleController extends AbstractController * Displays a form to edit an existing ignore origin instance rule entity. * * @Route("/{id}/edit", name="ignore_origin_instance_rules_edit", methods={"GET", "POST"}) + * @IsGranted("EDIT", subject="ignoreOriginInstanceRule") * * @return Response */ @@ -112,6 +116,7 @@ class IgnoreOriginInstanceRuleController extends AbstractController * Deletes a site credential entity. * * @Route("/{id}", name="ignore_origin_instance_rules_delete", methods={"DELETE"}) + * @IsGranted("DELETE", subject="ignoreOriginInstanceRule") * * @return RedirectResponse */ diff --git a/src/Security/Voter/AdminVoter.php b/src/Security/Voter/AdminVoter.php index 2351ec4cc..f4d6dda68 100644 --- a/src/Security/Voter/AdminVoter.php +++ b/src/Security/Voter/AdminVoter.php @@ -11,6 +11,8 @@ class AdminVoter extends Voter { public const LIST_USERS = 'LIST_USERS'; public const CREATE_USERS = 'CREATE_USERS'; + public const LIST_IGNORE_ORIGIN_INSTANCE_RULES = 'LIST_IGNORE_ORIGIN_INSTANCE_RULES'; + public const CREATE_IGNORE_ORIGIN_INSTANCE_RULES = 'CREATE_IGNORE_ORIGIN_INSTANCE_RULES'; private Security $security; @@ -21,7 +23,7 @@ class AdminVoter extends Voter protected function supports(string $attribute, $subject): bool { - if (!\in_array($attribute, [self::LIST_USERS, self::CREATE_USERS], true)) { + if (!\in_array($attribute, [self::LIST_USERS, self::CREATE_USERS, self::LIST_IGNORE_ORIGIN_INSTANCE_RULES, self::CREATE_IGNORE_ORIGIN_INSTANCE_RULES], true)) { return false; } @@ -39,6 +41,8 @@ class AdminVoter extends Voter switch ($attribute) { case self::LIST_USERS: case self::CREATE_USERS: + case self::LIST_IGNORE_ORIGIN_INSTANCE_RULES: + case self::CREATE_IGNORE_ORIGIN_INSTANCE_RULES: return $this->security->isGranted('ROLE_SUPER_ADMIN'); } diff --git a/src/Security/Voter/IgnoreOriginInstanceRuleVoter.php b/src/Security/Voter/IgnoreOriginInstanceRuleVoter.php new file mode 100644 index 000000000..d8ccf88e6 --- /dev/null +++ b/src/Security/Voter/IgnoreOriginInstanceRuleVoter.php @@ -0,0 +1,45 @@ +security = $security; + } + + protected function supports(string $attribute, $subject): bool + { + if (!$subject instanceof IgnoreOriginInstanceRule) { + return false; + } + + if (!\in_array($attribute, [self::EDIT, self::DELETE], true)) { + return false; + } + + return true; + } + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool + { + switch ($attribute) { + case self::EDIT: + case self::DELETE: + return $this->security->isGranted('ROLE_SUPER_ADMIN'); + } + + return false; + } +} diff --git a/templates/IgnoreOriginInstanceRule/edit.html.twig b/templates/IgnoreOriginInstanceRule/edit.html.twig index 8b2183652..2a8593526 100644 --- a/templates/IgnoreOriginInstanceRule/edit.html.twig +++ b/templates/IgnoreOriginInstanceRule/edit.html.twig @@ -28,11 +28,13 @@ {{ form_widget(edit_form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} {{ form_widget(edit_form._token) }} -

- {{ form_start(delete_form) }} - - {{ form_end(delete_form) }} -

+ {% if is_granted('DELETE', rule) %} +

+ {{ form_start(delete_form) }} + + {{ form_end(delete_form) }} +

+ {% endif %}

{{ 'ignore_origin_instance_rule.form.back_to_list'|trans }}

diff --git a/templates/IgnoreOriginInstanceRule/index.html.twig b/templates/IgnoreOriginInstanceRule/index.html.twig index 4e5f7187e..88de51645 100644 --- a/templates/IgnoreOriginInstanceRule/index.html.twig +++ b/templates/IgnoreOriginInstanceRule/index.html.twig @@ -23,16 +23,20 @@ {{ rule.rule }} - {{ 'ignore_origin_instance_rule.list.edit_action'|trans }} + {% if is_granted('EDIT', rule) %} + {{ 'ignore_origin_instance_rule.list.edit_action'|trans }} + {% endif %} {% endfor %} -
-

- {{ 'ignore_origin_instance_rule.list.create_new_one'|trans }} -

+ {% if is_granted('CREATE_IGNORE_ORIGIN_INSTANCE_RULES') %} +
+

+ {{ 'ignore_origin_instance_rule.list.create_new_one'|trans }} +

+ {% endif %} diff --git a/templates/layout.html.twig b/templates/layout.html.twig index 5acca264a..70e9b1589 100644 --- a/templates/layout.html.twig +++ b/templates/layout.html.twig @@ -124,12 +124,19 @@
  • vpn_key {{ 'menu.left.site_credentials'|trans }}
  • {% endif %}
  • - {% if is_granted('LIST_USERS') %} + {% set can_list_user = is_granted('LIST_USERS') %} + {% set is_super_admin = is_granted('ROLE_SUPER_ADMIN') %} + {% set can_list_ignore_origin_instance_rules = is_granted('LIST_IGNORE_ORIGIN_INSTANCE_RULES') %} + {% if can_list_user %}
  • people{{ 'menu.left.users_management'|trans }}
  • {% endif %} - {% if is_granted('ROLE_SUPER_ADMIN') %} + {% if is_super_admin %}
  • settings {{ 'menu.left.internal_settings'|trans }}
  • + {% endif %} + {% if can_list_ignore_origin_instance_rules %}
  • build {{ 'menu.left.ignore_origin_instance_rules'|trans }}
  • + {% endif %} + {% if can_list_user or is_super_admin or can_list_ignore_origin_instance_rules %}
  • {% endif %}
  • diff --git a/tests/Security/Voter/AdminVoterTest.php b/tests/Security/Voter/AdminVoterTest.php index 50f9ec39d..605e5a3b6 100644 --- a/tests/Security/Voter/AdminVoterTest.php +++ b/tests/Security/Voter/AdminVoterTest.php @@ -64,4 +64,32 @@ class AdminVoterTest extends TestCase $this->assertSame(VoterInterface::ACCESS_GRANTED, $this->adminVoter->vote($this->token, null, [AdminVoter::CREATE_USERS])); } + + public function testVoteReturnsDeniedForNonSuperAdminListIgnoreOriginInstanceRules(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(false); + + $this->assertSame(VoterInterface::ACCESS_DENIED, $this->adminVoter->vote($this->token, null, [AdminVoter::LIST_IGNORE_ORIGIN_INSTANCE_RULES])); + } + + public function testVoteReturnsGrantedForSuperAdminListIgnoreOriginInstanceRules(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(true); + + $this->assertSame(VoterInterface::ACCESS_GRANTED, $this->adminVoter->vote($this->token, null, [AdminVoter::LIST_IGNORE_ORIGIN_INSTANCE_RULES])); + } + + public function testVoteReturnsDeniedForNonSuperAdminCreateIgnoreOriginInstanceRules(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(false); + + $this->assertSame(VoterInterface::ACCESS_DENIED, $this->adminVoter->vote($this->token, null, [AdminVoter::CREATE_IGNORE_ORIGIN_INSTANCE_RULES])); + } + + public function testVoteReturnsGrantedForSuperAdminCreateIgnoreOriginInstanceRules(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(true); + + $this->assertSame(VoterInterface::ACCESS_GRANTED, $this->adminVoter->vote($this->token, null, [AdminVoter::CREATE_IGNORE_ORIGIN_INSTANCE_RULES])); + } } diff --git a/tests/Security/Voter/IgnoreOriginInstanceRuleVoterTest.php b/tests/Security/Voter/IgnoreOriginInstanceRuleVoterTest.php new file mode 100644 index 000000000..c17a6f328 --- /dev/null +++ b/tests/Security/Voter/IgnoreOriginInstanceRuleVoterTest.php @@ -0,0 +1,66 @@ +security = $this->createMock(Security::class); + + $this->token = $this->createMock(TokenInterface::class); + $this->token->method('getUser')->willReturn(new User()); + + $this->ignoreOriginInstanceRuleVoter = new IgnoreOriginInstanceRuleVoter($this->security); + } + + public function testVoteReturnsAbstainForInvalidSubject(): void + { + $this->assertSame(VoterInterface::ACCESS_ABSTAIN, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new \stdClass(), [IgnoreOriginInstanceRuleVoter::EDIT])); + } + + public function testVoteReturnsAbstainForInvalidAttribute(): void + { + $this->assertSame(VoterInterface::ACCESS_ABSTAIN, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new IgnoreOriginInstanceRule(), ['INVALID'])); + } + + public function testVoteReturnsDeniedForNonSuperAdminEdit(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(false); + + $this->assertSame(VoterInterface::ACCESS_DENIED, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new IgnoreOriginInstanceRule(), [IgnoreOriginInstanceRuleVoter::EDIT])); + } + + public function testVoteReturnsGrantedForSuperAdminEdit(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(true); + + $this->assertSame(VoterInterface::ACCESS_GRANTED, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new IgnoreOriginInstanceRule(), [IgnoreOriginInstanceRuleVoter::EDIT])); + } + + public function testVoteReturnsDeniedForNonSuperAdminDelete(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(false); + + $this->assertSame(VoterInterface::ACCESS_DENIED, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new IgnoreOriginInstanceRule(), [IgnoreOriginInstanceRuleVoter::DELETE])); + } + + public function testVoteReturnsGrantedForSuperAdminDelete(): void + { + $this->security->method('isGranted')->with('ROLE_SUPER_ADMIN')->willReturn(true); + + $this->assertSame(VoterInterface::ACCESS_GRANTED, $this->ignoreOriginInstanceRuleVoter->vote($this->token, new IgnoreOriginInstanceRule(), [IgnoreOriginInstanceRuleVoter::DELETE])); + } +}