Skip to content

Commit 35cbbc0

Browse files
committed
[HttpFoundation] Add #[IsSignatureValid] attribute
1 parent d076526 commit 35cbbc0

File tree

15 files changed

+482
-0
lines changed

15 files changed

+482
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Allow using their name without added suffix when using `#[Target]` for custom services
99
* Deprecate `Symfony\Bundle\FrameworkBundle\Console\Application::add()` in favor of `Symfony\Bundle\FrameworkBundle\Console\Application::addCommand()`
1010
* Add `assertEmailAddressNotContains()` to the `MailerAssertionsTrait`
11+
* Add autoconfiguration tag `security.uri_signer` to `Symfony\Component\HttpFoundation\UriSigner`
1112

1213
7.3
1314
---

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class UnusedTagsPass implements CompilerPassInterface
8989
'security.authenticator.login_linker',
9090
'security.expression_language_provider',
9191
'security.remember_me_handler',
92+
'security.uri_signer',
9293
'security.voter',
9394
'serializer.encoder',
9495
'serializer.normalizer',

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
use Symfony\Component\HttpClient\ThrottlingHttpClient;
9999
use Symfony\Component\HttpClient\UriTemplateHttpClient;
100100
use Symfony\Component\HttpFoundation\Request;
101+
use Symfony\Component\HttpFoundation\UriSigner;
101102
use Symfony\Component\HttpKernel\Attribute\AsController;
102103
use Symfony\Component\HttpKernel\Attribute\AsTargetedValueResolver;
103104
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
@@ -749,6 +750,8 @@ public function load(array $configs, ContainerBuilder $container): void
749750
->addTag('mime.mime_type_guesser');
750751
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
751752
->addMethodCall('setLogger', [new Reference('logger')]);
753+
$container->registerForAutoconfiguration(UriSigner::class)
754+
->addTag('security.uri_signer');
752755

753756
$container->registerAttributeForAutoconfiguration(AsEventListener::class, static function (ChildDefinition $definition, AsEventListener $attribute, \ReflectionClass|\ReflectionMethod $reflector) {
754757
$tagAttributes = get_object_vars($attribute);

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticator;
6565
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener;
6666
use Symfony\Component\Security\Http\Event\CheckPassportEvent;
67+
use Symfony\Component\Security\Http\EventListener\IsSignatureValidAttributeListener;
6768

6869
/**
6970
* SecurityExtension.
@@ -134,6 +135,9 @@ public function load(array $configs, ContainerBuilder $container): void
134135
$container->removeDefinition('form.type_extension.form.password_hasher');
135136
$container->removeDefinition('form.type_extension.password.password_hasher');
136137
}
138+
if (!class_exists(IsSignatureValidAttributeListener::class)) {
139+
$container->removeDefinition('controller.is_signature_valid_attribute_listener');
140+
}
137141

138142
// set some global scalars
139143
$container->setParameter('security.access.denied_url', $config['access_denied_url']);

src/Symfony/Bundle/SecurityBundle/Resources/config/security.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
use Symfony\Component\Security\Http\Controller\SecurityTokenValueResolver;
4949
use Symfony\Component\Security\Http\Controller\UserValueResolver;
5050
use Symfony\Component\Security\Http\EventListener\IsGrantedAttributeListener;
51+
use Symfony\Component\Security\Http\EventListener\IsSignatureValidAttributeListener;
5152
use Symfony\Component\Security\Http\Firewall;
5253
use Symfony\Component\Security\Http\FirewallMapInterface;
5354
use Symfony\Component\Security\Http\HttpUtils;
@@ -323,5 +324,12 @@
323324
->set('cache.security_is_csrf_token_valid_attribute_expression_language')
324325
->parent('cache.system')
325326
->tag('cache.pool')
327+
328+
->set('controller.is_signature_valid_attribute_listener', IsSignatureValidAttributeListener::class)
329+
->args([
330+
service('uri_signer'),
331+
tagged_locator('security.uri_signer'),
332+
])
333+
->tag('kernel.event_subscriber')
326334
;
327335
};

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Deprecate using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
8+
* Add `#[WithHttpStatus]` to define status codes: 404 for `SignedUriException` and 403 for `ExpiredSignedUriException`
89

910
7.3
1011
---

src/Symfony/Component/HttpFoundation/Exception/ExpiredSignedUriException.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111

1212
namespace Symfony\Component\HttpFoundation\Exception;
1313

14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
16+
1417
/**
1518
* @author Kevin Bond <kevinbond@gmail.com>
1619
*/
20+
#[WithHttpStatus(Response::HTTP_FORBIDDEN)]
1721
final class ExpiredSignedUriException extends SignedUriException
1822
{
1923
/**

src/Symfony/Component/HttpFoundation/Exception/SignedUriException.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111

1212
namespace Symfony\Component\HttpFoundation\Exception;
1313

14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
16+
1417
/**
1518
* @author Kevin Bond <kevinbond@gmail.com>
1619
*/
20+
#[WithHttpStatus(Response::HTTP_NOT_FOUND)]
1721
abstract class SignedUriException extends \RuntimeException implements ExceptionInterface
1822
{
1923
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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\Component\Security\Http\Attribute;
13+
14+
use Symfony\Component\HttpFoundation\UriSigner;
15+
16+
/**
17+
* Validates the request signature for specific HTTP methods.
18+
*
19+
* This class determines whether a request's signature should be validated
20+
* based on the configured HTTP methods. If the request method matches one
21+
* of the specified methods (or if no methods are specified), the signature
22+
* is checked.
23+
*
24+
* If the signature is invalid, a {@see \Symfony\Component\HttpFoundation\Exception\SignedUriException}
25+
* is thrown during validation.
26+
*
27+
* @author Santiago San Martin <sanmartindev@gmail.com>
28+
*/
29+
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)]
30+
final class IsSignatureValid
31+
{
32+
public readonly array $methods;
33+
public readonly ?string $signer;
34+
35+
/**
36+
* @param string[]|string $methods HTTP methods that require signature validation. An empty array means that no method filtering is done
37+
* @param string $signer The ID of the UriSigner service to use for signature validation. Defaults to 'uri_signer'
38+
*
39+
* @throws \LogicException If the UriSigner class does not support the 'verify' method (requires symfony/http-foundation >= 7.3)
40+
*/
41+
public function __construct(
42+
array|string $methods = [],
43+
?string $signer = null,
44+
) {
45+
if (!method_exists(UriSigner::class, 'verify')) {
46+
throw new \LogicException('The `IsSignatureValid` attribute requires symfony/http-foundation >= 7.3.');
47+
}
48+
49+
$this->methods = (array) $methods;
50+
$this->signer = $signer;
51+
}
52+
}

src/Symfony/Component/Security/Http/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Deprecate callable firewall listeners, extend `AbstractListener` or implement `FirewallListenerInterface` instead
88
* Deprecate `AbstractListener::__invoke`
9+
* Add `#[IsSignatureValid]` attribute to validate URI signatures
910

1011
7.3
1112
---

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy