From c7765263778e8ecdd192388abbf60e52513f3c24 Mon Sep 17 00:00:00 2001 From: Christopher Georg Date: Mon, 4 Sep 2023 10:57:13 +0200 Subject: [PATCH 1/3] feat: migrate to "lcobucci/jwt" v5 feat: add support for psr/clock --- Services/JWSProvider/LcobucciJWSProvider.php | 46 +++++++------------- Tests/Functional/GetTokenTest.php | 10 ++--- composer.json | 2 +- 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/Services/JWSProvider/LcobucciJWSProvider.php b/Services/JWSProvider/LcobucciJWSProvider.php index 74dfa51e..3eb5e045 100644 --- a/Services/JWSProvider/LcobucciJWSProvider.php +++ b/Services/JWSProvider/LcobucciJWSProvider.php @@ -2,14 +2,10 @@ namespace Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider; -use Lcobucci\Clock\Clock; -use Lcobucci\Clock\SystemClock; use Lcobucci\JWT\Builder; use Lcobucci\JWT\Encoding\ChainedFormatter; use Lcobucci\JWT\Encoding\JoseEncoder; -use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer; -use Lcobucci\JWT\Signer\Ecdsa; use Lcobucci\JWT\Signer\Hmac; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha384; @@ -21,11 +17,13 @@ use Lcobucci\JWT\Token\RegisteredClaims; use Lcobucci\JWT\Validation\Constraint\LooseValidAt; use Lcobucci\JWT\Validation\Constraint\SignedWith; -use Lcobucci\JWT\Validation\Constraint\ValidAt; +use Lcobucci\JWT\Validation\ValidAt; use Lcobucci\JWT\Validation\Validator; use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\KeyLoaderInterface; use Lexik\Bundle\JWTAuthenticationBundle\Signature\CreatedJWS; use Lexik\Bundle\JWTAuthenticationBundle\Signature\LoadedJWS; +use Symfony\Component\Clock\Clock; +use Symfony\Component\Clock\ClockInterface; /** * @final @@ -36,7 +34,7 @@ class LcobucciJWSProvider implements JWSProviderInterface { private KeyLoaderInterface $keyLoader; - private Clock $clock; + private ClockInterface $clock; private Signer $signer; @@ -49,10 +47,10 @@ class LcobucciJWSProvider implements JWSProviderInterface /** * @throws \InvalidArgumentException If the given crypto engine is not supported */ - public function __construct(KeyLoaderInterface $keyLoader, string $signatureAlgorithm, ?int $ttl, ?int $clockSkew, bool $allowNoExpiration = false, Clock $clock = null) + public function __construct(KeyLoaderInterface $keyLoader, string $signatureAlgorithm, ?int $ttl, ?int $clockSkew, bool $allowNoExpiration = false, ClockInterface $clock = null) { if (null === $clock) { - $clock = SystemClock::fromUTC(); + $clock = new Clock(); } $this->keyLoader = $keyLoader; @@ -66,36 +64,32 @@ public function __construct(KeyLoaderInterface $keyLoader, string $signatureAlgo /** * {@inheritdoc} */ - public function create(array $payload, array $header = []) + public function create(array $payload, array $header = []): CreatedJWS { - if (class_exists(JWTBuilder::class)) { - $jws = new JWTBuilder(new JoseEncoder(), ChainedFormatter::default()); - } else { - $jws = new Builder(); - } + $jws = new JWTBuilder(new JoseEncoder(), ChainedFormatter::default()); foreach ($header as $k => $v) { - $jws->withHeader($k, $v); + $jws = $jws->withHeader($k, $v); } - $now = time(); + $now = $this->clock->now()->getTimestamp(); $issuedAt = $payload['iat'] ?? $now; unset($payload['iat']); - $jws->issuedAt(!$issuedAt instanceof \DateTimeImmutable ? new \DateTimeImmutable("@{$issuedAt}") : $issuedAt); + $jws = $jws->issuedAt(!$issuedAt instanceof \DateTimeImmutable ? new \DateTimeImmutable("@{$issuedAt}") : $issuedAt); if (null !== $this->ttl || isset($payload['exp'])) { $exp = $payload['exp'] ?? $now + $this->ttl; unset($payload['exp']); if ($exp) { - $jws->expiresAt($exp instanceof \DateTimeImmutable ? $exp : (new \DateTimeImmutable("@$exp"))); + $jws = $jws->expiresAt($exp instanceof \DateTimeImmutable ? $exp : (new \DateTimeImmutable("@$exp"))); } } if (isset($payload['sub'])) { - $jws->relatedTo($payload['sub']); + $jws = $jws->relatedTo($payload['sub']); unset($payload['sub']); } @@ -104,7 +98,7 @@ public function create(array $payload, array $header = []) } foreach ($payload as $name => $value) { - $jws->withClaim($name, $value); + $jws = $jws->withClaim($name, $value); } $e = $token = null; @@ -119,13 +113,9 @@ public function create(array $payload, array $header = []) /** * {@inheritdoc} */ - public function load($token) + public function load($token): LoadedJWS { - if (class_exists(JWTParser::class)) { - $jws = (new JWTParser(new JoseEncoder()))->parse($token); - } else { - $jws = (new Parser())->parse($token); - } + $jws = (new JWTParser(new JoseEncoder()))->parse($token); $payload = []; @@ -165,10 +155,6 @@ private function getSignerForAlgorithm($signatureAlgorithm): Signer $signerClass = $signerMap[$signatureAlgorithm]; - if (is_subclass_of($signerClass, Ecdsa::class) && method_exists($signerClass, 'create')) { - return $signerClass::create(); - } - return new $signerClass(); } diff --git a/Tests/Functional/GetTokenTest.php b/Tests/Functional/GetTokenTest.php index bc438f3f..e5f8889a 100644 --- a/Tests/Functional/GetTokenTest.php +++ b/Tests/Functional/GetTokenTest.php @@ -3,7 +3,6 @@ namespace Lexik\Bundle\JWTAuthenticationBundle\Tests\Functional; use Lcobucci\JWT\Encoding\JoseEncoder; -use Lcobucci\JWT\Parser; use Lcobucci\JWT\Token\Parser as JWTParser; use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent; use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent; @@ -70,14 +69,11 @@ public function testGetTokenWithCustomClaim() $this->assertArrayHasKey('custom', $payload, 'The payload should contains a "custom" claim.'); $this->assertSame('dummy', $payload['custom'], 'The "custom" claim should be equal to "dummy".'); - if (class_exists(JWTParser::class)) { - $parser = new JWTParser(new JoseEncoder()); - } else { - $parser = new Parser(); - } + $parser = new JWTParser(new JoseEncoder()); + $jws = $parser->parse($token); - $this->assertArrayHasKey('foo', method_exists($jws, 'headers') ? $jws->headers()->all() : $jws->getHeaders(), 'The payload should contains a custom "foo" header.'); + $this->assertArrayHasKey('foo', $jws->headers()->all(), 'The payload should contains a custom "foo" header.'); } public function testGetTokenFromInvalidCredentials() diff --git a/composer.json b/composer.json index 96d686b0..4341c6a4 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "require": { "php": ">=8.1", "ext-openssl": "*", - "lcobucci/jwt": "^3.4|^4.0", + "lcobucci/jwt": "^5.0", "symfony/config": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/deprecation-contracts": "^2.4|^3.0", From 9655820984927374e1d412baed14db5b647b4f82 Mon Sep 17 00:00:00 2001 From: Christopher Georg Date: Mon, 4 Sep 2023 11:22:52 +0200 Subject: [PATCH 2/3] feat: migrate to "lcobucci/jwt" v5 feat: add support for psr/clock --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 4341c6a4..ccac4e12 100644 --- a/composer.json +++ b/composer.json @@ -53,6 +53,7 @@ "require-dev": { "phpunit/phpunit": "^9.5", "symfony/browser-kit": "^5.4|^6.0", + "symfony/clock": "^6.3", "symfony/console": "^5.4|^6.0", "symfony/dom-crawler": "^5.4|^6.0", "symfony/filesystem": "^5.4|^6.0", From 543e943a6028d2b17b2c8fb8c33a8478bc2c061e Mon Sep 17 00:00:00 2001 From: Christopher Georg Date: Mon, 4 Sep 2023 11:34:42 +0200 Subject: [PATCH 3/3] feat: migrate to "lcobucci/jwt" v5 feat: add support for psr/clock --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e20737d..6e94cb49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,7 @@ jobs: with: php-version: "${{ matrix.php }}" tools: "composer:v2,flex" + extensions: sodium - name: "Set Composer stability" if: "matrix.symfony == '6.3.*@dev'"