8000 minor #59407 [TwigBridge] Align isGrantedForUser on isGranted with fa… · symfonyaml/symfony@5fca27b · GitHub
[go: up one dir, main page]

Skip to content

Commit 5fca27b

Browse files
minor symfony#59407 [TwigBridge] Align isGrantedForUser on isGranted with falsy $field (smnandre)
This PR was squashed before being merged into the 7.3 branch. Discussion ---------- [TwigBridge] Align isGrantedForUser on isGranted with falsy $field | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Issues | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exists, explain below instead --> | License | MIT Align `is_granted_for_user` on `is_granted` behaviour when passing a falsy $field argument. (Follows symfony#59282 (comment)) Commits ------- cc92b65 [TwigBridge] Align isGrantedForUser on isGranted with falsy $field
2 parents dde4a2e + cc92b65 commit 5fca27b

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

src/Symfony/Bridge/Twig/Extension/SecurityExtension.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ public function isGranted(mixed $role, mixed $object = null, ?string $field = nu
4141
}
4242

4343
if (null !== $field) {
44+
if (!class_exists(FieldVote::class)) {
45+
throw new \LogicException('Passing a $field to the "is_granted()" function requires symfony/acl. Try running "composer require symfony/acl-bundle" if you need field-level access control.');
46+
}
47+
4448
$object = new FieldVote($object, $field);
4549
}
4650

@@ -57,7 +61,11 @@ public function isGrantedForUser(UserInterface $user, mixed $attribute, mixed $s
5761
throw new \LogicException(\sprintf('An instance of "%s" must be provided to use "%s()".', UserAuthorizationCheckerInterface::class, __METHOD__));
5862
}
5963

60-
if ($field) {
64+
if (null !== $field) {
65+
if (!class_exists(FieldVote::class)) {
66+
throw new \LogicException('Passing a $field to the "is_granted_for_user()" function requires symfony/acl. Try running "composer require symfony/acl-bundle" if you need field-level access control.');
67+
}
68+
6169
$subject = new FieldVote($subject, $field);
6270
}
6371

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Tests\Extension;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ClassExistsMock;
16+
use Symfony\Bridge\Twig\Extension\SecurityExtension;
17+
use Symfony\Component\Security\Acl\Voter\FieldVote;
18+
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
19+
use Symfony\Component\Security\Core\Authorization\UserAuthorizationCheckerInterface;
20+
use Symfony\Component\Security\Core\User\UserInterface;
21+
22+
class SecurityExtensionTest extends TestCase
23+
{
24+
/**
25+
* @dataProvider provideObjectFieldAclCases
26+
*/
27+
public function testIsGrantedCreatesFieldVoteObjectWhenFieldNotNull($object, $field, $expectedSubject)
28+
{
29+
$securityChecker = $this->createMock(AuthorizationCheckerInterface::class);
30+
$securityChecker
31+
->expects($this->once())
32+
->method('isGranted')
33+
->with('ROLE', $expectedSubject)
34+
->willReturn(true);
35+
36+
$securityExtension = new SecurityExtension($securityChecker);
37+
$this->assertTrue($securityExtension->isGranted('ROLE', $object, $field));
38+
}
39+
40+
public function testIsGrantedThrowsWhenFieldNotNullAndFieldVoteClassDoesNotExist()
41+
{
42+
if (!class_exists(UserAuthorizationCheckerInterface::class)) {
43+
$this->markTestSkipped('This test requires symfony/security-core 7.3 or superior.');
44+
}
45+
46+
$securityChecker = $this->createMock(AuthorizationCheckerInterface::class);
47+
48+
ClassExistsMock::register(SecurityExtension::class);
49+
ClassExistsMock::withMockedClasses([FieldVote::class => false]);
50+
51+
$this->expectException(\LogicException::class);
52+
$this->expectExceptionMessageMatches('Passing a $field to the "is_granted()" function requires symfony/acl.');
53+
54+
$securityExtension = new SecurityExtension($securityChecker);
55+
$securityExtension->isGranted('ROLE', 'object', 'bar');
56+
}
57+
58+
/**
59+
* @dataProvider provideObjectFieldAclCases
60+
*/
61+
public function testIsGrantedForUserCreatesFieldVoteObjectWhenFieldNotNull($object, $field, $expectedSubject)
62+
{
63+
if (!class_exists(UserAuthorizationCheckerInterface::class)) {
64+
$this->markTestSkipped('This test requires symfony/security-core 7.3 or superior.');
65+
}
66+
67+
$user = $this->createMock(UserInterface::class);
68+
$userSecurityChecker = $this->createMock(UserAuthorizationCheckerInterface::class);
69+
$userSecurityChecker
70+
->expects($this->once())
71+
->method('isGrantedForUser')
72+
->with($user, 'ROLE', $expectedSubject)
73+
->willReturn(true);
74+
75+
$securityExtension = new SecurityExtension(null, null, $userSecurityChecker);
76+
$this->assertTrue($securityExtension->isGrantedForUser($user, 'ROLE', $object, $field));
77+
}
78+
79+
public function testIsGrantedForUserThrowsWhenFieldNotNullAndFieldVoteClassDoesNotExist()
80+
{
81+
if (!class_exists(UserAuthorizationCheckerInterface::class)) {
82+
$this->markTestSkipped('This test requires symfony/security-core 7.3 or superior.');
83+
}
84+
85+
$securityChecker = $this->createMock(UserAuthorizationCheckerInterface::class);
86+
87+
ClassExistsMock::register(SecurityExtension::class);
88+
ClassExistsMock::withMockedClasses([FieldVote::class => false]);
89+
90+
$this->expectException(\LogicException::class);
91+
$this->expectExceptionMessageMatches('Passing a $field to the "is_granted_for_user()" function requires symfony/acl.');
92+
93+
$securityExtension = new SecurityExtension(null, null, $securityChecker);
94+
$securityExtension->isGrantedForUser($this->createMock(UserInterface::class), 'object', 'bar');
95+
}
96+
97+
public static function provideObjectFieldAclCases()
98+
{
99+
return [
100+
[null, null, null],
101+
['object', null, 'object'],
102+
['object', false, new FieldVote('object', false)],
103+
['object', 0, new FieldVote('object', 0)],
104+
['object', '', new FieldVote('object', '')],
105+
['object', 'field', new FieldVote('object', 'field')],
106+
];
107+
}
108+
}

0 commit comments

Comments
 (0)
0