Skip to content

Commit 807aba0

Browse files
Merge branch '7.4' into 8.0
* 7.4: (31 commits) [Validator] Update Romanian translations fix tests [JsonStreamer] Fix decoding iterable lists [String][Inflector] Fix edge cases [Serializer][Validator] Add JSON schema for validating and autocompleting YAML config files [DependencyInjection] Allow adding resource tags using any config formats Fix merge Add missing Sweego Mailer Bridge webhook events [Security] Fix attribute-based chained user providers [Intl] Fix Intl::getIcuStubVersion() [Intl] Add methods to filter currencies more precisely [Notifier] Add tests for option classes Sync intl scripts [Intl] Add metadata about currencies' validtity dates Bump Symfony version to 7.3.4 Update VERSION for 7.3.3 Update CHANGELOG for 7.3.3 Bump Symfony version to 6.4.26 Update VERSION for 6.4.25 Update CONTRIBUTORS for 6.4.25 ...
2 parents 9016ce6 + 5cef36b commit 807aba0

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CHANGELOG
1818
* Deprecate callable firewall listeners, extend `AbstractListener` or implement `FirewallListenerInterface` instead
1919
* Deprecate `AbstractListener::__invoke`
2020
* Add `$methods` argument to `#[IsGranted]` to restrict validation to specific HTTP methods
21-
* Remove `final` keyword from `#[IsGranted]` to allow implementation of custom attributes
21+
* Allow subclassing `#[IsGranted]`
2222

2323
7.3
2424
---

EventListener/IsGrantedAttributeListener.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@ public function __construct(
3939

4040
public function onKernelControllerArguments(ControllerArgumentsEvent $event): void
4141
{
42-
if (!$attributes = $event->getAttributes(IsGranted::class)) {
42+
$attributes = [];
43+
foreach ($event->getAttributes() as $class => $attributes[]) {
44+
if (!is_a($class, IsGranted::class, true)) {
45+
array_pop($attributes);
46+
}
47+
}
48+
49+
if (!$attributes = array_merge(...$attributes)) {
4350
return;
4451
}
4552

Tests/EventListener/IsGrantedAttributeListenerTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
3030
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
3131
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
32+
use Symfony\Component\Security\Http\Attribute\IsGranted;
3233
use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener;
3334
use Symfony\Component\Security\Http\Tests\Fixtures\IsGrantedAttributeController;
3435
use Symfony\Component\Security\Http\Tests\Fixtures\IsGrantedAttributeMethodsController;
@@ -524,4 +525,59 @@ public function testSkipsAuthorizationWhenMethodDoesNotMatchStringConstraint()
524525
$listener = new IsGrantedAttributeListener($authChecker);
525526
$listener->onKernelControllerArguments($event);
526527
}
528+
529+
public function testFiltersOnlyIsGrantedAttributesUsingInstanceof()
530+
{
531+
$authChecker = $this->createMock(AuthorizationCheckerInterface::class);
532+
$authChecker->expects($this->once())
533+
->method('isGranted')
534+
->with('ROLE_ADMIN')
535+
->willReturn(true);
536+
537+
$controller = [new IsGrantedAttributeMethodsController(), 'admin'];
538+
$event = new ControllerArgumentsEvent(
539+
$this->createMock(HttpKernelInterface::class),
540+
$controller,
541+
[],
542+
new Request(),
543+
null
544+
);
545+
546+
// Inject mixed attributes: one IsGranted and one unrelated object; only IsGranted should be processed
547+
$event->setController($controller, [
548+
IsGranted::class => [new IsGranted('ROLE_ADMIN')],
549+
\stdClass::class => [new \stdClass()],
550+
]);
551+
552+
$listener = new IsGrantedAttributeListener($authChecker);
553+
$listener->onKernelControllerArguments($event);
554+
}
555+
556+
public function testSupportsSubclassOfIsGrantedViaInstanceof()
557+
{
558+
$authChecker = $this->createMock(AuthorizationCheckerInterface::class);
559+
$authChecker->expects($this->once())
560+
->method('isGranted')
561+
->with('ROLE_ADMIN')
562+
->willReturn(true);
563+
564+
$controller = [new IsGrantedAttributeMethodsController(), 'admin'];
565+
$event = new ControllerArgumentsEvent(
566+
$this->createMock(HttpKernelInterface::class),
567+
$controller,
568+
[],
569+
new Request(),
570+
null
571+
);
572+
573+
$custom = new class('ROLE_ADMIN') extends IsGranted {};
574+
575+
// Inject subclass instance; instanceof IsGranted should match
576+
$event->setController($controller, [
577+
$custom::class => [$custom],
578+
]);
579+
580+
$listener = new IsGrantedAttributeListener($authChecker);
581+
$listener->onKernelControllerArguments($event);
582+
}
527583
}

0 commit comments

Comments
 (0)