From 86c484f46c9b998492cda2c24ecbde271bf853eb Mon Sep 17 00:00:00 2001 From: mhepburn Date: Wed, 20 Apr 2022 13:28:40 +0100 Subject: [PATCH 1/5] Allow additional public keys to be set by value, as well as by path --- Services/KeyLoader/AbstractKeyLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Services/KeyLoader/AbstractKeyLoader.php b/Services/KeyLoader/AbstractKeyLoader.php index 082f0778..7577634c 100644 --- a/Services/KeyLoader/AbstractKeyLoader.php +++ b/Services/KeyLoader/AbstractKeyLoader.php @@ -47,7 +47,7 @@ public function getAdditionalPublicKeys(): array $contents = []; foreach ($this->additionalPublicKeys as $key) { - if (!$key || !is_file($key) || !is_readable($key)) { + if (!$key && (!is_file($key) || !is_readable($key))) { throw new \RuntimeException(sprintf('Additional public key "%s" does not exist or is not readable. Did you correctly set the "lexik_jwt_authentication.additional_public_keys" configuration key?', $key)); } From ebc259226841f7d081e87a77a4f30155c2ecf57f Mon Sep 17 00:00:00 2001 From: mhepburn Date: Wed, 20 Apr 2022 14:52:05 +0100 Subject: [PATCH 2/5] Adds test case for null additional key --- Services/KeyLoader/AbstractKeyLoader.php | 7 +++++-- Tests/Services/KeyLoader/AbstractTestKeyLoader.php | 14 ++++++++++++++ Tests/Services/KeyLoader/OpenSSLKeyLoaderTest.php | 5 +++++ Tests/Services/KeyLoader/RawKeyLoaderTest.php | 5 +++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Services/KeyLoader/AbstractKeyLoader.php b/Services/KeyLoader/AbstractKeyLoader.php index 7577634c..0a424517 100644 --- a/Services/KeyLoader/AbstractKeyLoader.php +++ b/Services/KeyLoader/AbstractKeyLoader.php @@ -47,8 +47,11 @@ public function getAdditionalPublicKeys(): array $contents = []; foreach ($this->additionalPublicKeys as $key) { - if (!$key && (!is_file($key) || !is_readable($key))) { - throw new \RuntimeException(sprintf('Additional public key "%s" does not exist or is not readable. Did you correctly set the "lexik_jwt_authentication.additional_public_keys" configuration key?', $key)); + if (!$key) { + throw new \RuntimeException(sprintf('Additional public key is not set correctly. Check the "lexik_jwt_authentication.additional_public_keys" configuration key', $key)); + } + if (is_file($key) && !is_readable($key)) { + throw new \RuntimeException(sprintf('Additional public key "%s" is not readable. Did you correctly set the "lexik_jwt_authentication.additional_public_keys" configuration key?', $key)); } $contents[] = is_file($key) ? file_get_contents($key) : $key; diff --git a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php index 15065f9a..a9f816a7 100644 --- a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php +++ b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\JWTAuthenticationBundle\Tests\Services\KeyLoader; +use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\AbstractKeyLoader; use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\KeyLoaderInterface; use Lexik\Bundle\JWTAuthenticationBundle\Tests\ForwardCompatTestCaseTrait; use PHPUnit\Framework\TestCase; @@ -34,6 +35,17 @@ public function testLoadKeyFromWrongType() $this->keyLoader->loadKey('wrongType'); } + public function testLoadingNullAdditionalPublicKey() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Additional public key is not set correctly. Check the "lexik_jwt_authentication.additional_public_keys" configuration key'); + + $className = $this->getClassName(); + /** @var AbstractKeyLoader $loader */ + $loader = new $className('private.pem', 'public.pem', 'foobar', [null]); + $loader->getAdditionalPublicKeys(); + } + /** * {@inheritdoc} */ @@ -60,4 +72,6 @@ protected function removeKeysIfExist() unlink($privateKey); } } + + abstract protected function getClassName(): string; } diff --git a/Tests/Services/KeyLoader/OpenSSLKeyLoaderTest.php b/Tests/Services/KeyLoader/OpenSSLKeyLoaderTest.php index d53a60eb..aae7d9a9 100644 --- a/Tests/Services/KeyLoader/OpenSSLKeyLoaderTest.php +++ b/Tests/Services/KeyLoader/OpenSSLKeyLoaderTest.php @@ -42,4 +42,9 @@ public function testLoadInvalidPrivateKey() $this->keyLoader->loadKey('private'); } + + protected function getClassName(): string + { + return OpenSSLKeyLoader::class; + } } diff --git a/Tests/Services/KeyLoader/RawKeyLoaderTest.php b/Tests/Services/KeyLoader/RawKeyLoaderTest.php index 87fdc8d4..10809b9b 100644 --- a/Tests/Services/KeyLoader/RawKeyLoaderTest.php +++ b/Tests/Services/KeyLoader/RawKeyLoaderTest.php @@ -27,4 +27,9 @@ public function testLoadPrivateKey() { $this->assertSame('private.pem', $this->keyLoader->loadKey('private')); } + + protected function getClassName(): string + { + return RawKeyLoader::class; + } } From 11bf6c41d3bbecc6a93a70dadcf154340a053f6b Mon Sep 17 00:00:00 2001 From: mhepburn Date: Wed, 20 Apr 2022 15:02:58 +0100 Subject: [PATCH 3/5] Adds test cases for loading keys as files or as strings --- .../KeyLoader/AbstractTestKeyLoader.php | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php index a9f816a7..9d7d1e0a 100644 --- a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php +++ b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php @@ -46,6 +46,40 @@ public function testLoadingNullAdditionalPublicKey() $loader->getAdditionalPublicKeys(); } + public function testLoadingAdditionalPublicKeysAsStrings() + { + $additionalPublicKeys = ['myKeyText1', 'myKeyText2']; + + $className = $this->getClassName(); + /** @var AbstractKeyLoader $loader */ + $loader = new $className('private.pem', 'public.pem', 'foobar', $additionalPublicKeys); + + $this->assertSame($additionalPublicKeys, $loader->getAdditionalPublicKeys()); + } + + public function testLoadingAdditionalPublicKeysFromFiles() + { + file_put_contents('additional-public-1.pem', 'myKeyTextFromFile1'); + file_put_contents('additional-public-2.pem', 'myKeyTextFromFile2'); + + $className = $this->getClassName(); + /** @var AbstractKeyLoader $loader */ + $loader = new $className('private.pem', 'public.pem', 'foobar', ['additional-public-1.pem', 'additional-public-2.pem']); + + $this->assertSame(['myKeyTextFromFile1', 'myKeyTextFromFile2'], $loader->getAdditionalPublicKeys()); + } + + public function testLoadingAdditionalPublicKeysFromFilesAndAsStrings() + { + file_put_contents('additional-public-1.pem', 'myKeyTextFromFile1'); + + $className = $this->getClassName(); + /** @var AbstractKeyLoader $loader */ + $loader = new $className('private.pem', 'public.pem', 'foobar', ['additional-public-1.pem', 'myKeyText2']); + + $this->assertSame(['myKeyTextFromFile1', 'myKeyText2'], $loader->getAdditionalPublicKeys()); + } + /** * {@inheritdoc} */ @@ -61,15 +95,11 @@ public function doTearDown() */ protected function removeKeysIfExist() { - $privateKey = 'private.pem'; - $publicKey = 'public.pem'; - - if (file_exists($publicKey)) { - unlink($publicKey); - } - - if (file_exists($privateKey)) { - unlink($privateKey); + $keys = ['private.pem', 'public.pem', 'additional-public-1.pem', 'additional-public-2.pem']; + foreach ($keys as $key) { + if (file_exists($key)) { + unlink($key); + } } } From 1f6c83c8bcddca975bb3026d1aad4c8e5da87ba3 Mon Sep 17 00:00:00 2001 From: mhepburn Date: Wed, 20 Apr 2022 20:25:29 +0100 Subject: [PATCH 4/5] Skip falsy keys, to make config more flexible --- Services/KeyLoader/AbstractKeyLoader.php | 2 +- Tests/Services/KeyLoader/AbstractTestKeyLoader.php | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Services/KeyLoader/AbstractKeyLoader.php b/Services/KeyLoader/AbstractKeyLoader.php index 0a424517..d62558b4 100644 --- a/Services/KeyLoader/AbstractKeyLoader.php +++ b/Services/KeyLoader/AbstractKeyLoader.php @@ -48,7 +48,7 @@ public function getAdditionalPublicKeys(): array foreach ($this->additionalPublicKeys as $key) { if (!$key) { - throw new \RuntimeException(sprintf('Additional public key is not set correctly. Check the "lexik_jwt_authentication.additional_public_keys" configuration key', $key)); + continue; } if (is_file($key) && !is_readable($key)) { throw new \RuntimeException(sprintf('Additional public key "%s" is not readable. Did you correctly set the "lexik_jwt_authentication.additional_public_keys" configuration key?', $key)); diff --git a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php index 9d7d1e0a..9b2b7f27 100644 --- a/Tests/Services/KeyLoader/AbstractTestKeyLoader.php +++ b/Tests/Services/KeyLoader/AbstractTestKeyLoader.php @@ -35,15 +35,12 @@ public function testLoadKeyFromWrongType() $this->keyLoader->loadKey('wrongType'); } - public function testLoadingNullAdditionalPublicKey() + public function testFalsyAdditionalPublicKeysSkipped() { - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage('Additional public key is not set correctly. Check the "lexik_jwt_authentication.additional_public_keys" configuration key'); - $className = $this->getClassName(); /** @var AbstractKeyLoader $loader */ - $loader = new $className('private.pem', 'public.pem', 'foobar', [null]); - $loader->getAdditionalPublicKeys(); + $loader = new $className('private.pem', 'public.pem', 'foobar', [null, false, '']); + $this->assertSame([], $loader->getAdditionalPublicKeys()); } public function testLoadingAdditionalPublicKeysAsStrings() From 015da58e20a313a533edd3bb6d684b2c4eda1112 Mon Sep 17 00:00:00 2001 From: mhepburn Date: Thu, 21 Apr 2022 08:25:54 +0100 Subject: [PATCH 5/5] Update documentation to note that keys can be passed as strings --- Resources/doc/1-configuration-reference.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/doc/1-configuration-reference.md b/Resources/doc/1-configuration-reference.md index 2a9e926d..42f2d7e6 100644 --- a/Resources/doc/1-configuration-reference.md +++ b/Resources/doc/1-configuration-reference.md @@ -16,10 +16,11 @@ lexik_jwt_authentication: public_key: '%kernel.project_dir%/config/jwt/public.pem' # path to the public key OR raw public key, required for verifying tokens pass_phrase: 'yourpassphrase' # required for creating tokens # Additional public keys are used to verify signature of incoming tokens, if the key provided in "public_key" configuration node doesn't verify the token + # Can be paths to public key files OR raw public keys additional_public_keys: - '%kernel.project_dir%/config/jwt/public1.pem' - '%kernel.project_dir%/config/jwt/public2.pem' - - '%kernel.project_dir%/config/jwt/public3.pem' + - '%env(PUBLIC3_KEY_TEXT)%' ``` #### Using HMAC