From 90eb89f4e9eda5e6d50001961d889b293f4c593e Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 6 Dec 2022 23:11:45 +0100 Subject: [PATCH] [HttpKernel] Fix CacheAttributeListener priority --- .../Functional/CacheAttributeListenerTest.php | 98 +++++++++++++++++++ .../app/CacheAttributeListener/bundles.php | 18 ++++ .../app/CacheAttributeListener/config.yml | 24 +++++ .../app/CacheAttributeListener/routing.yml | 3 + .../Bundle/FrameworkBundle/composer.json | 2 +- .../IsGrantedAttributeListener.php | 2 +- 6 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CacheAttributeListenerTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/bundles.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/config.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/routing.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CacheAttributeListenerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CacheAttributeListenerTest.php new file mode 100644 index 0000000000000..72b2c12266d87 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CacheAttributeListenerTest.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\Cache; +use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\Security\Core\User\InMemoryUser; +use Symfony\Component\Security\Http\Attribute\IsGranted; + +class CacheAttributeListenerTest extends AbstractWebTestCase +{ + public function testAnonimousUserWithEtag() + { + $client = self::createClient(['test_case' => 'CacheAttributeListener']); + + $client->request('GET', '/', server: ['HTTP_IF_NONE_MATCH' => sprintf('"%s"', hash('sha256', '12345'))]); + + self::assertTrue($client->getResponse()->isRedirect('http://localhost/login')); + } + + public function testAnonimousUserWithoutEtag() + { + $client = self::createClient(['test_case' => 'CacheAttributeListener']); + + $client->request('GET', '/'); + + self::assertTrue($client->getResponse()->isRedirect('http://localhost/login')); + } + + public function testLoggedInUserWithEtag() + { + $client = self::createClient(['test_case' => 'CacheAttributeListener']); + + $client->loginUser(new InMemoryUser('the-username', 'the-password', ['ROLE_USER'])); + $client->request('GET', '/', server: ['HTTP_IF_NONE_MATCH' => sprintf('"%s"', hash('sha256', '12345'))]); + + $response = $client->getResponse(); + + self::assertSame(304, $response->getStatusCode()); + self::assertSame('', $response->getContent()); + } + + public function testLoggedInUserWithoutEtag() + { + $client = self::createClient(['test_case' => 'CacheAttributeListener']); + + $client->loginUser(new InMemoryUser('the-username', 'the-password', ['ROLE_USER'])); + $client->request('GET', '/'); + + $response = $client->getResponse(); + + self::assertSame(200, $response->getStatusCode()); + self::assertSame('Hi there!', $response->getContent()); + } +} + +class TestEntityValueResolver implements ValueResolverInterface +{ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + return Post::class === $argument->getType() ? [new Post()] : []; + } +} + +class Post +{ + public function getId(): int + { + return 1; + } + + public function getEtag(): string + { + return '12345'; + } +} + +class WithAttributesController +{ + #[IsGranted('ROLE_USER')] + #[Cache(etag: 'post.getEtag()')] + public function __invoke(Post $post): Response + { + return new Response('Hi there!'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/bundles.php new file mode 100644 index 0000000000000..9a26fb163a77d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\SecurityBundle\SecurityBundle; + +return [ + new FrameworkBundle(), + new SecurityBundle(), +]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/config.yml new file mode 100644 index 0000000000000..21890451a1094 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/config.yml @@ -0,0 +1,24 @@ +imports: + - { resource: ../config/default.yml } + +services: + Symfony\Bundle\FrameworkBundle\Tests\Functional\TestEntityValueResolver: + tags: + - { name: controller.argument_value_resolver, priority: 110 } + + Symfony\Bundle\FrameworkBundle\Tests\Functional\WithAttributesController: + public: true + +security: + providers: + main: + memory: + users: + the-username: { password: the-password, roles: [ 'ROLE_USER' ] } + + firewalls: + main: + pattern: ^/ + form_login: + login_path: /login + provider: main diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/routing.yml new file mode 100644 index 0000000000000..50c37b823fcbe --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/CacheAttributeListener/routing.yml @@ -0,0 +1,3 @@ +with_attributes_controller: + path: / + controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\WithAttributesController diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 4ab6b2e919e32..00986c7854f08 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -26,7 +26,7 @@ "symfony/error-handler": "^6.1", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/http-foundation": "^6.2", - "symfony/http-kernel": "^6.2", + "symfony/http-kernel": "^6.2.1", "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", diff --git a/src/Symfony/Component/Security/Http/EventListener/IsGrantedAttributeListener.php b/src/Symfony/Component/Security/Http/EventListener/IsGrantedAttributeListener.php index ce8fbacb8c1cc..518578b511c9b 100644 --- a/src/Symfony/Component/Security/Http/EventListener/IsGrantedAttributeListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/IsGrantedAttributeListener.php @@ -77,7 +77,7 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event) public static function getSubscribedEvents(): array { - return [KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 10]]; + return [KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 20]]; } private function getIsGrantedSubject(string|Expression $subjectRef, Request $request, array $arguments): mixed