From 0a666e1e1284b6e204d8f08fedbcb0299c8ab47c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 14 Jun 2024 03:03:10 +0200 Subject: [PATCH] Extract public key from private pem file at runtime --- .env.dist | 4 +- .../Tokens/Algorithms/AlgorithmInterface.php | 2 - api/components/Tokens/Algorithms/ES256.php | 61 ++++++------------- api/components/Tokens/Algorithms/HS256.php | 4 -- api/components/Tokens/AlgorithmsManager.php | 11 ++-- api/components/Tokens/Component.php | 17 +----- api/config/config-test.php | 1 - api/config/config.php | 1 - api/tests/_data/certs/public.pem | 4 -- composer.json | 1 + composer.lock | 3 +- data/certs/public.pem | 4 -- 12 files changed, 33 insertions(+), 80 deletions(-) delete mode 100644 api/tests/_data/certs/public.pem delete mode 100644 data/certs/public.pem diff --git a/.env.dist b/.env.dist index 6b2a010..6ec156a 100644 --- a/.env.dist +++ b/.env.dist @@ -9,8 +9,8 @@ EMAILS_RENDERER_HOST=http://emails-renderer:3000 ## Security params JWT_USER_SECRET=replace_me_for_production JWT_ENCRYPTION_KEY=thisisadummyvalue32latterslength -JWT_PRIVATE_PEM_LOCATION= -JWT_PUBLIC_PEM_LOCATION= +JWT_PRIVATE_KEY_PATH= +JWT_PRIVATE_KEY_PASS= ## External services CHRLY_HOST=skinsystem.ely.by diff --git a/api/components/Tokens/Algorithms/AlgorithmInterface.php b/api/components/Tokens/Algorithms/AlgorithmInterface.php index a7e36ae..c37565f 100644 --- a/api/components/Tokens/Algorithms/AlgorithmInterface.php +++ b/api/components/Tokens/Algorithms/AlgorithmInterface.php @@ -8,8 +8,6 @@ use Lcobucci\JWT\Signer\Key; interface AlgorithmInterface { - public function getAlgorithmId(): string; - public function getSigner(): Signer; public function getPrivateKey(): Key; diff --git a/api/components/Tokens/Algorithms/ES256.php b/api/components/Tokens/Algorithms/ES256.php index 7d5dd66..03ff262 100644 --- a/api/components/Tokens/Algorithms/ES256.php +++ b/api/components/Tokens/Algorithms/ES256.php @@ -7,68 +7,45 @@ use Lcobucci\JWT\Signer; use Lcobucci\JWT\Signer\Ecdsa\Sha256; use Lcobucci\JWT\Signer\Key; -class ES256 implements AlgorithmInterface { +final class ES256 implements AlgorithmInterface { - /** - * @var string - */ - private $privateKey; + private string $privateKeyPath; - /** - * @var string|null - */ - private $privateKeyPass; + private ?string $privateKeyPass; - /** - * @var string - */ - private $publicKey; + private ?Key $privateKey = null; - /** - * @var Key|null - */ - private $loadedPrivateKey; + private ?Key $publicKey = null; - /** - * @var Key|null - */ - private $loadedPublicKey; + private Sha256 $signer; - /** - * TODO: document arguments - * - * @param string $privateKey - * @param string|null $privateKeyPass - * @param string $publicKey - */ - public function __construct(string $privateKey, ?string $privateKeyPass, string $publicKey) { - $this->privateKey = $privateKey; + public function __construct(string $privateKeyPath, ?string $privateKeyPass = null) { + $this->privateKeyPath = $privateKeyPath; $this->privateKeyPass = $privateKeyPass; - $this->publicKey = $publicKey; - } - - public function getAlgorithmId(): string { - return 'ES256'; + $this->signer = new Sha256(); } public function getSigner(): Signer { - return new Sha256(); + return $this->signer; } public function getPrivateKey(): Key { - if ($this->loadedPrivateKey === null) { - $this->loadedPrivateKey = new Key($this->privateKey, $this->privateKeyPass); + if ($this->privateKey === null) { + $this->privateKey = new Key($this->privateKeyPath, $this->privateKeyPass); } - return $this->loadedPrivateKey; + return $this->privateKey; } public function getPublicKey(): Key { - if ($this->loadedPublicKey === null) { - $this->loadedPublicKey = new Key($this->publicKey); + if ($this->publicKey === null) { + $privateKey = $this->getPrivateKey(); + $privateKeyOpenSSL = openssl_pkey_get_private($privateKey->getContent(), $privateKey->getPassphrase() ?? ''); + $publicPem = openssl_pkey_get_details($privateKeyOpenSSL)['key']; + $this->publicKey = new Key($publicPem); } - return $this->loadedPublicKey; + return $this->publicKey; } } diff --git a/api/components/Tokens/Algorithms/HS256.php b/api/components/Tokens/Algorithms/HS256.php index 2bc7e66..a62a736 100644 --- a/api/components/Tokens/Algorithms/HS256.php +++ b/api/components/Tokens/Algorithms/HS256.php @@ -23,10 +23,6 @@ class HS256 implements AlgorithmInterface { $this->key = $key; } - public function getAlgorithmId(): string { - return 'HS256'; - } - public function getSigner(): Signer { return new Sha256(); } diff --git a/api/components/Tokens/AlgorithmsManager.php b/api/components/Tokens/AlgorithmsManager.php index af9d074..7d1bb3c 100644 --- a/api/components/Tokens/AlgorithmsManager.php +++ b/api/components/Tokens/AlgorithmsManager.php @@ -6,21 +6,24 @@ namespace api\components\Tokens; use api\components\Tokens\Algorithms\AlgorithmInterface; use Webmozart\Assert\Assert; -class AlgorithmsManager { +final class AlgorithmsManager { /** * @var AlgorithmInterface[] */ - private $algorithms = []; + private array $algorithms = []; + /** + * @param AlgorithmInterface[] $algorithms + */ public function __construct(array $algorithms = []) { array_map([$this, 'add'], $algorithms); } public function add(AlgorithmInterface $algorithm): self { - $id = $algorithm->getAlgorithmId(); + $id = $algorithm->getSigner()->getAlgorithmId(); Assert::keyNotExists($this->algorithms, $id, 'passed algorithm is already exists'); - $this->algorithms[$algorithm->getSigner()->getAlgorithmId()] = $algorithm; + $this->algorithms[$id] = $algorithm; return $this; } diff --git a/api/components/Tokens/Component.php b/api/components/Tokens/Component.php index a1460e4..56795c5 100644 --- a/api/components/Tokens/Component.php +++ b/api/components/Tokens/Component.php @@ -25,11 +25,6 @@ class Component extends BaseComponent { */ public $hmacKey; - /** - * @var string - */ - public $publicKeyPath; - /** * @var string */ @@ -45,16 +40,12 @@ class Component extends BaseComponent { */ public $encryptionKey; - /** - * @var AlgorithmsManager|null - */ - private $algorithmManager; + private ?AlgorithmsManager $algorithmManager = null; public function init(): void { parent::init(); Assert::notEmpty($this->hmacKey, 'hmacKey must be set'); Assert::notEmpty($this->privateKeyPath, 'privateKeyPath must be set'); - Assert::notEmpty($this->publicKeyPath, 'publicKeyPath must be set'); Assert::notEmpty($this->encryptionKey, 'encryptionKey must be set'); } @@ -131,11 +122,7 @@ class Component extends BaseComponent { if ($this->algorithmManager === null) { $this->algorithmManager = new AlgorithmsManager([ new Algorithms\HS256($this->hmacKey), - new Algorithms\ES256( - "file://{$this->privateKeyPath}", - $this->privateKeyPass, - "file://{$this->publicKeyPath}" - ), + new Algorithms\ES256("file://{$this->privateKeyPath}", $this->privateKeyPass), ]); } diff --git a/api/config/config-test.php b/api/config/config-test.php index 0a855dc..119d03b 100644 --- a/api/config/config-test.php +++ b/api/config/config-test.php @@ -5,7 +5,6 @@ return [ 'hmacKey' => 'tests-secret-key', 'privateKeyPath' => codecept_data_dir('certs/private.pem'), 'privateKeyPass' => null, - 'publicKeyPath' => codecept_data_dir('certs/public.pem'), 'encryptionKey' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', ], 'reCaptcha' => [ diff --git a/api/config/config.php b/api/config/config.php index 4b60905..d9c239a 100644 --- a/api/config/config.php +++ b/api/config/config.php @@ -34,7 +34,6 @@ return [ 'hmacKey' => getenv('JWT_USER_SECRET'), 'privateKeyPath' => getenv('JWT_PRIVATE_KEY_PATH') ?: __DIR__ . '/../../data/certs/private.pem', 'privateKeyPass' => getenv('JWT_PRIVATE_KEY_PASS') ?: null, - 'publicKeyPath' => getenv('JWT_PUBLIC_KEY_PATH') ?: __DIR__ . '/../../data/certs/public.pem', 'encryptionKey' => getenv('JWT_ENCRYPTION_KEY'), ], 'tokensFactory' => [ diff --git a/api/tests/_data/certs/public.pem b/api/tests/_data/certs/public.pem deleted file mode 100644 index 684c55a..0000000 --- a/api/tests/_data/certs/public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES2Pyq9r0CyyviLaWwq0ki5uy8hr/ -ZbNO++3j4XP43uLD9/GYkrKGIRl+Hu5HT+LwZvrFcEaVhPk5CvtV4zlYJg== ------END PUBLIC KEY----- diff --git a/composer.json b/composer.json index 7454357..125fb65 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", + "ext-openssl": "*", "ext-pdo": "*", "ext-simplexml": "*", "ext-sodium": "*", diff --git a/composer.lock b/composer.lock index f78cc2d..9cc1a42 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3885d09d6c24355b0c314fc3259d185b", + "content-hash": "b8103011e139d9bd760edc1e2505b75f", "packages": [ { "name": "bacon/bacon-qr-code", @@ -6999,6 +6999,7 @@ "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", + "ext-openssl": "*", "ext-pdo": "*", "ext-simplexml": "*", "ext-sodium": "*" diff --git a/data/certs/public.pem b/data/certs/public.pem deleted file mode 100644 index aeb8f26..0000000 --- a/data/certs/public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEv6ENZA59mzFvoDKTX3BI3Nx6di+x -WnsOAo9+zx0hnMnfzdhOS930ocFTBcyZmmF7iM7nhGicfiDfJKIyV8w+BA== ------END PUBLIC KEY-----