8000 feature #60222 [FrameworkBundle][HttpFoundation] Add Clock support fo… · symfony/symfony@904df78 · GitHub
[go: up one dir, main page]

Skip to content
  • Commit 904df78

    Browse files
    committed
    feature #60222 [FrameworkBundle][HttpFoundation] Add Clock support for UriSigner (kbond)
    This PR was merged into the 7.3 branch. Discussion ---------- [FrameworkBundle][HttpFoundation] Add Clock support for `UriSigner` | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | n/a | License | MIT Optionally adds the ability to inject a `ClockInterface` to `UriSigner` (mostly to help with testing). The framework-bundle wires this up if possible. Commits ------- 4566f3a [HttpFoundation][FrameworkBundle] clock support for `UriSigner`
    2 parents ed7dba6 + 4566f3a commit 904df78

    File tree

    5 files changed

    +38
    -2
    lines changed

    5 files changed

    +38
    -2
    lines changed

    src/Symfony/Bundle/FrameworkBundle/Resources/config/services.php

    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -158,6 +158,9 @@ class_exists(WorkflowEvents::class) ? WorkflowEvents::ALIASES : []
    158158
    ->set('uri_signer', UriSigner::class)
    159159
    ->args([
    160160
    new Parameter('kernel.secret'),
    161+
    '_hash',
    162+
    '_expiration',
    163+
    service('clock')->nullOnInvalid(),
    161164
    ])
    162165
    ->lazy()
    163166
    ->alias(UriSigner::class, 'uri_signer')

    src/Symfony/Component/HttpFoundation/CHANGELOG.md

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -8,6 +8,7 @@ CHANGELOG
    88
    * Add `EventStreamResponse` and `ServerEvent` classes to streamline server event streaming
    99
    * Add support for `valkey:` / `valkeys:` schemes for sessions
    1010
    * `Request::getPreferredLanguage()` now favors a more preferred language above exactly matching a locale
    11+
    * Allow `UriSigner` to use a `ClockInterface`
    1112

    1213
    7.2
    1314
    ---

    src/Symfony/Component/HttpFoundation/Tests/UriSignerTest.php

    Lines changed: 24 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -12,6 +12,7 @@
    1212
    namespace Symfony\Component\HttpFoundation\Tests;
    1313

    1414
    use PHPUnit\Framework\TestCase;
    15+
    use Symfony\Component\Clock\MockClock;
    1516
    use Symfony\Component\HttpFoundation\Exception\LogicException;
    1617
    use Symfony\Component\HttpFoundation\Request;
    1718
    use Symfony\Component\HttpFoundation\UriSigner;
    @@ -199,6 +200,29 @@ public function testCheckWithUriExpiration()
    199200
    $this->assertFalse($signer->check($relativeUriFromNow3));
    200201
    }
    201202

    203+
    public function testCheckWithUriExpirationWithClock()
    204+
    {
    205+
    $clock = new MockClock();
    206+
    $signer = new UriSigner('foobar', clock: $clock);
    207+
    208+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo', new \DateTimeImmutable('2000-01-01 00:00:00'))));
    209+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar', new \DateTimeImmutable('2000-01-01 00:00:00'))));
    210+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer', new \DateTimeImmutable('2000-01-01 00:00:00'))));
    211+
    212+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo', 1577836800))); // 2000-01-01
    213+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar', 1577836800))); // 2000-01-01
    214+
    $this->assertFalse($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer', 1577836800))); // 2000-01-01
    215+
    216+
    $relativeUriFromNow1 = $signer->sign('http://example.com/foo', new \DateInterval('PT3S'));
    217+
    $relativeUriFromNow2 = $signer->sign('http://example.com/foo?foo=bar', new \DateInterval('PT3S'));
    218+
    $relativeUriFromNow3 = $signer->sign('http://example.com/foo?foo=bar&0=integer', new \DateInterval('PT3S'));
    219+
    $clock->sleep(10);
    220+
    221+
    $this->assertFalse($signer->check($relativeUriFromNow1));
    222+
    $this->assertFalse($signer->check($relativeUriFromNow2));
    223+
    $this->assertFalse($signer->check($relativeUriFromNow3));
    224+
    }
    225+
    202226
    public function testNonUrlSafeBase64()
    203227
    {
    204228
    $signer = new UriSigner('foobar');

    src/Symfony/Component/HttpFoundation/UriSigner.php

    Lines changed: 9 additions & 2 deletions
    97F5
    Original file line numberDiff line numberDiff line change
    @@ -11,6 +11,7 @@
    1111

    1212
    namespace Symfony\Component\HttpFoundation;
    1313

    14+
    use Psr\Clock\ClockInterface;
    1415
    use Symfony\Component\HttpFoundation\Exception\LogicException;
    1516

    1617
    /**
    @@ -26,6 +27,7 @@ public function __construct(
    2627
    #[\SensitiveParameter] private string $secret,
    2728
    private string $hashParameter = '_hash',
    2829
    private string $expirationParameter = '_expiration',
    30+
    private ?ClockInterface $clock = null,
    2931
    ) {
    3032
    if (!$secret) {
    3133
    throw new \InvalidArgumentException('A non-empty secret is required.');
    @@ -109,7 +111,7 @@ public function check(string $uri): bool
    109111
    }
    110112

    111113
    if ($expiration = $params[$this->expirationParameter] ?? false) {
    112-
    return time() < $expiratio 57AE n;
    114+
    return $this->now()->getTimestamp() < $expiration;
    113115
    }
    114116

    115117
    return true;
    @@ -153,9 +155,14 @@ private function getExpirationTime(\DateTimeInterface|\DateInterval|int $expirat
    153155
    }
    154156

    155157
    if ($expiration instanceof \DateInterval) {
    156-
    return \DateTimeImmutable::createFromFormat('U', time())->add($expiration)->format('U');
    158+
    return $this->now()->add($expiration)->format('U');
    157159
    }
    158160

    159161
    return (string) $expiration;
    160162
    }
    163+
    164+
    private function now(): \DateTimeImmutable
    165+
    {
    166+
    return $this->clock?->now() ?? \DateTimeImmutable::createFromFormat('U', time());
    167+
    }
    161168
    }

    src/Symfony/Component/HttpFoundation/composer.json

    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -25,6 +25,7 @@
    2525
    "doctrine/dbal": "^3.6|^4",
    2626
    "predis/predis": "^1.1|^2.0",
    2727
    "symfony/cache": "^6.4.12|^7.1.5",
    28+
    "symfony/clock": "^6.4|^7.0",
    2829
    "symfony/dependency-injection": "^6.4|^7.0",
    2930
    "symfony/http-kernel": "^6.4|^7.0",
    3031
    "symfony/mime": "^6.4|^7.0",

    0 commit comments

    Comments
     (0)
    0