Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ca672e7

Browse filesBrowse files
committed
add capability to answer VoteObject
psalm errors
1 parent 8dc32f7 commit ca672e7
Copy full SHA for ca672e7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

46 files changed

+1021
-85
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/Extension/SecurityExtension.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public function isGranted(mixed $role, mixed $object = null, ?string $field = nu
4545
}
4646

4747
try {
48+
/* @var bool */
4849
return $this->securityChecker->isGranted($role, $object);
4950
} catch (AuthenticationCredentialsNotFoundException) {
5051
return false;

‎src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php
+21-1Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
3636
use Symfony\Component\Routing\RouterInterface;
3737
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
38+
use Symfony\Component\Security\Core\Authorization\AccessDecision;
3839
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
3940
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
4041
use Symfony\Component\Security\Core\User\UserInterface;
@@ -202,6 +203,22 @@ protected function isGranted(mixed $attribute, mixed $subject = null): bool
202203
return $this->container->get('security.authorization_checker')->isGranted($attribute, $subject);
203204
}
204205

206+
/**
207+
* Checks if the attribute is granted against the current authentication token and optionally supplied subject.
208+
*
209+
* @throws \LogicException
210+
*/
211+
protected function getAccessDecision(mixed $attribute, mixed $subject = null): AccessDecision
212+
{
213+
if (!$this->container->has('security.authorization_checker')) {
214+
throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
215+
}
216+
217+
$decision = $this->container->get('security.authorization_checker')->isGranted($attribute, $subject, AccessDecision::RETURN_AS_OBJECT);
218+
219+
return $decision instanceof AccessDecision ? $decision : new AccessDecision($decision);
220+
}
221+
205222
/**
206223
* Throws an exception unless the attribute is granted against the current authentication token and optionally
207224
* supplied subject.
@@ -210,10 +227,13 @@ protected function isGranted(mixed $attribute, mixed $subject = null): bool
210227
*/
211228
protected function denyAccessUnlessGranted(mixed $attribute, mixed $subject = null, string $message = 'Access Denied.'): void
212229
{
213-
if (!$this->isGranted($attribute, $subject)) {
230+
$decision = $this->getAccessDecision($attribute, $subject);
231+
232+
if ($decision->isDenied()) {
214233
$exception = $this->createAccessDeniedException($message);
215234
$exception->setAttributes([$attribute]);
216235
$exception->setSubject($subject);
236+
$exception->setAccessDecision($decision);
217237

218238
throw $exception;
219239
}

‎src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php
+35-1Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
use Symfony\Component\Routing\RouterInterface;
4141
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
4242
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
43+
use Symfony\Component\Security\Core\Authorization\AccessDecision;
4344
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
45+
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
4446
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
4547
use Symfony\Component\Security\Core\User\InMemoryUser;
4648
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
@@ -362,7 +364,14 @@ public function testdenyAccessUnlessGranted()
362364

363365
$this->expectException(AccessDeniedException::class);
364366

365-
$controller->denyAccessUnlessGranted('foo');
367+
try {
368+
$controller->denyAccessUnlessGranted('foo');
369+
} catch (AccessDeniedException $exception) {
370+
$this->assertFalse($exception->getAccessDecision()->getAccess());
371+
$this->assertEmpty($exception->getAccessDecision()->getVotes());
372+
$this->assertEmpty($exception->getAccessDecision()->getMessage());
373+
throw $exception;
374+
}
366375
}
367376

368377
/**
@@ -644,4 +653,29 @@ public function testSendEarlyHints()
644653

645654
$this->assertSame('</style.css>; rel="preload"; as="stylesheet",</script.js>; rel="preload"; as="script"', $response->headers->get('Link'));
646655
}
656+
657+
public function testdenyAccessUnlessGrantedWithAccessDecisionObject()
658+
{
659+
$authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class);
660+
$authorizationChecker->expects($this->once())
661+
->method('isGranted')
662+
->willReturn(new AccessDecision(false, [new Vote(-1)], 'access denied'));
663+
664+
$container = new Container();
665+
$container->set('security.authorization_checker', $authorizationChecker);
666+
667+
$controller = $this->createController();
668+
$controller->setContainer($container);
669+
670+
$this->expectException(AccessDeniedException::class);
671+
672+
try {
673+
$controller->denyAccessUnlessGranted('foo');
674+
} catch (AccessDeniedException $exception) {
675+
$this->assertFalse($exception->getAccessDecision()->getAccess());
676+
$this->assertCount(1, $exception->getAccessDecision()->getVotes());
677+
$this->assertSame('access denied', $exception->getAccessDecision()->getMessage());
678+
throw $exception;
679+
}
680+
}
647681
}

‎src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
2121
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
2222
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
23+
use Symfony\Component\Security\Core\Authorization\AccessDecision;
2324
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
2425
use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager;
2526
use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter;
27+
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
28+
use Symfony\Component\Security\Core\Authorization\Voter\VoteInterface;
2629
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
2730
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
2831
use Symfony\Component\Security\Http\FirewallMapInterface;
@@ -138,6 +141,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
138141

139142
// collect voter details
140143
$decisionLog = $this->accessDecisionManager->getDecisionLog();
144+
141145
foreach ($decisionLog as $key => $log) {
142146
$decisionLog[$key]['voter_details'] = [];
143147
foreach ($log['voterDetails'] as $voterDetail) {
@@ -146,10 +150,14 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
146150
$decisionLog[$key]['voter_details'][] = [
147151
'class' => $classData,
148152
'attributes' => $voterDetail['attributes'], // Only displayed for unanimous strategy
149-
'vote' => $voterDetail['vote'],
153+
'vote' => $voterDetail['vote'] instanceof VoteInterface ? $voterDetail['vote'] : new Vote($voterDetail['vote']),
150154
];
151155
}
152156
unset($decisionLog[$key]['voterDetails']);
157+
158+
if (!$decisionLog[$key]['result'] instanceof AccessDecision) {
159+
$decisionLog[$key]['result'] = new AccessDecision($decisionLog[$key]['result']);
160+
}
153161
}
154162

155163
$this->data['access_decision_log'] = $decisionLog;

‎src/Symfony/Bundle/SecurityBundle/EventListener/VoteListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/EventListener/VoteListener.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function __construct(
3131

3232
public function onVoterVote(VoteEvent $event): void
3333
{
34-
$this->traceableAccessDecisionManager->addVoterVote($event->getVoter(), $event->getAttributes(), $event->getVote());
34+
$this->traceableAccessDecisionManager->addVoterVote($event->getVoter(), $event->getAttributes(), $event->getVote(true));
3535
}
3636

3737
public static function getSubscribedEvents(): array

‎src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig
+12-6Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -518,14 +518,16 @@
518518
<col style="width: 30px">
519519
<col style="width: 120px">
520520
<col style="width: 25%">
521-
<col style="width: 60%">
521+
<col style="width: 40%">
522+
<col style="width: 20%">
522523

523524
<thead>
524525
<tr>
525526
<th>#</th>
526527
<th>Result</th>
527528
<th>Attributes</th>
528529
<th>Object</th>
530+
<th>Message</th>
529531
</tr>
530532
</thead>
531533

@@ -534,7 +536,7 @@
534536
<tr class="voter_result">
535537
<td class="font-normal text-small text-muted nowrap">{{ loop.index }}</td>
536538
<td class="font-normal">
537-
{{ decision.result
539+
{{ decision.result.access
538540
? '<span class="label status-success same-width">GRANTED</span>'
539541
: '<span class="label status-error same-width">DENIED</span>'
540542
}}
@@ -554,6 +556,7 @@
554556
{% endif %}
555557
</td>
556558
<td>{{ profiler_dump(decision.seek('object')) }}</td>
559+
<td>{{ decision.result.message }}</td>
557560
</tr>
558561
<tr class="voter_details">
559562
<td></td>
@@ -570,14 +573,17 @@
570573
<td class="font-normal text-small">attribute {{ voter_detail['attributes'][0] }}</td>
571574
{% endif %}
572575
<td class="font-normal text-small">
573-
{% if voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_GRANTED') %}
576+
{% if voter_detail['vote'].access == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_GRANTED') %}
574577
ACCESS GRANTED
575-
{% elseif voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_ABSTAIN') %}
578+
{% elseif voter_detail['vote'].access == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_ABSTAIN') %}
576579
ACCESS ABSTAIN
577-
{% elseif voter_detail['vote'] == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_DENIED') %}
580+
{% elseif voter_detail['vote'].access == constant('Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::ACCESS_DENIED') %}
578581
ACCESS DENIED
579582
{% else %}
580-
unknown ({{ voter_detail['vote'] }})
583+
unknown ({{ voter_detail['vote'].access }})
584+
{% endif %}
585+
{% if voter_detail['vote'].messages is not empty %}
586+
: {{ voter_detail['vote'].messages | join(', ') }}
581587
{% endif %}
582588
</td>
583589
</tr>

‎src/Symfony/Bundle/SecurityBundle/Security.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Security.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ public function getUser(): ?UserInterface
5858
/**
5959
* Checks if the attributes are granted against the current authentication token and optionally supplied subject.
6060
*/
61-
public function isGranted(mixed $attributes, mixed $subject = null): bool
61+
public function isGranted(mixed $attributes, mixed $subject = null, $asObject = false): bool
6262
{
6363
return $this->container->get('security.authorization_checker')
64-
->isGranted($attributes, $subject);
64+
->isGranted($attributes, $subject, $asObject);
6565
}
6666

6767
public function getToken(): ?TokenInterface

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.