From 30b1cfffa2670c86b4e17149a4b3b155e2861af8 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 12:50:40 +0200 Subject: [PATCH 01/12] feat: NCCER publish to two solar tenants --- .../Repository/PlatformKeyChainRepository.php | 85 ++++++++++++++----- .../PlatformKeyChainRepositoryTest.php | 13 +-- 2 files changed, 69 insertions(+), 29 deletions(-) diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 5ce33091..a2e64e85 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -50,15 +50,33 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain */ public function save(KeyChainInterface $keyChain): void { + $isKeyFound = false; + + $options = $this->getOptions(); + foreach ($options as $configs) { + $id = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; + + if ($id === $keyChain->getIdentifier()) { + $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $isKeyFound = true; + + break; + } + } + if (!$isKeyFound) { + throw new ErrorException('Impossible to write LTI keys. Configuration not found'); + } + $isPublicKeySaved = $this->getFileSystem() ->put( - ltrim($this->getOption(self::OPTION_DEFAULT_PUBLIC_KEY_PATH), DIRECTORY_SEPARATOR), + ltrim($publicKey, DIRECTORY_SEPARATOR), $keyChain->getPublicKey()->getContent() ); $isPrivateKeySaved = $this->getFileSystem() ->put( - ltrim($this->getOption(self::OPTION_DEFAULT_PRIVATE_KEY_PATH), DIRECTORY_SEPARATOR), + ltrim($privateKey, DIRECTORY_SEPARATOR), $keyChain->getPrivateKey()->getContent() ); @@ -69,7 +87,8 @@ public function save(KeyChainInterface $keyChain): void public function getDefaultKeyId(): string { - return $this->getOption(PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, ''); + $options = $this->getOptions(); + return reset($options)[self::OPTION_DEFAULT_KEY_ID] ?? ''; } /** @@ -77,15 +96,27 @@ public function getDefaultKeyId(): string */ public function find(string $identifier): ?KeyChainInterface { - if ($identifier !== $this->getDefaultKeyId()) { - return null; + $isKeyFound = false; + $options = $this->getOptions(); + foreach ($options as $configs) { + $defaultKeyId = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; + + if ($defaultKeyId === $identifier) { + $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $keyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; + $isKeyFound = true; + + break; + } } - $publicKey = $this->getFileSystem() - ->read($this->getOption(self::OPTION_DEFAULT_PUBLIC_KEY_PATH)); + if (!$isKeyFound) { + return null; + } - $privateKey = $this->getFileSystem() - ->read($this->getOption(self::OPTION_DEFAULT_PRIVATE_KEY_PATH)); + $publicKey = $this->getFileSystem()->read($publicKey); + $privateKey = $this->getFileSystem()->read($privateKey); if ($publicKey === false || $privateKey === false) { throw new ErrorException('Impossible to read LTI keys'); @@ -93,7 +124,7 @@ public function find(string $identifier): ?KeyChainInterface return new KeyChain( $this->getDefaultKeyId(), - $this->getOption(self::OPTION_DEFAULT_KEY_NAME), + $keyName, new Key($publicKey), new Key($privateKey) ); @@ -101,24 +132,32 @@ public function find(string $identifier): ?KeyChainInterface public function findAll(KeyChainQuery $query): KeyChainCollection { - $publicKey = $this->getFileSystem() - ->read($this->getOption(self::OPTION_DEFAULT_PUBLIC_KEY_PATH)); + $options = $this->getOptions(); + foreach ($options as $configs) { + $defaultKeyId = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; + $defaultKeyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; + $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + + if ($defaultKeyId) { + $publicKey = $this->getFileSystem()->read($publicKey); + $privateKey = $this->getFileSystem()->read($privateKey); + + $keyChains = new TaoKeyChain( + $defaultKeyId, + $defaultKeyName, + new TaoKey($publicKey), + new TaoKey($privateKey) + ); + } - $privateKey = $this->getFileSystem() - ->read($this->getOption(self::OPTION_DEFAULT_PRIVATE_KEY_PATH)); + } - if ($publicKey === false || $privateKey === false) { + if (empty($keyChains)) { throw new ErrorException('Impossible to read LTI keys'); } - $keyChain = new TaoKeyChain( - $this->getOption(self::OPTION_DEFAULT_KEY_ID), - $this->getOption(self::OPTION_DEFAULT_KEY_NAME), - new TaoKey($publicKey), - new TaoKey($privateKey) - ); - - return new KeyChainCollection($keyChain); + return new KeyChainCollection($keyChains); } diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 6e79e8e7..03d64010 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -51,12 +51,13 @@ public function setUp(): void $fileSystem->method('getFileSystem') ->willReturn($this->fileSystem); - $this->subject = new PlatformKeyChainRepository( - [ - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId', - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', - PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', - PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', + $this->subject = new PlatformKeyChainRepository([ + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', + ] ] ); $this->subject->setServiceLocator( From bd479c9bb16f98ffbae8775913fb7d46b87fae28 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 18:17:58 +0200 Subject: [PATCH 02/12] feat: NCCER publish to two solar tenants --- .../PlatformKeyChainRepository.conf.php | 13 ++-- .../Version202402271423013774_taoLti.php | 34 +++++++++++ .../Service/CachedKeyChainGenerator.php | 2 +- .../CachedPlatformKeyChainRepository.php | 6 +- .../Repository/PlatformKeyChainRepository.php | 60 +++++++++---------- .../Service/CachedKeyChainGeneratorTest.php | 2 +- .../CachedPlatformKeyChainRepositoryTest.php | 4 +- .../PlatformKeyChainRepositoryTest.php | 48 ++++++++++----- 8 files changed, 107 insertions(+), 62 deletions(-) create mode 100644 migrations/Version202402271423013774_taoLti.php diff --git a/config/default/PlatformKeyChainRepository.conf.php b/config/default/PlatformKeyChainRepository.conf.php index 25c5156d..173eed4f 100644 --- a/config/default/PlatformKeyChainRepository.conf.php +++ b/config/default/PlatformKeyChainRepository.conf.php @@ -2,11 +2,12 @@ use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; -return new PlatformKeyChainRepository( - [ - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'defaultPlatformKeyId', - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'defaultPlatformKeyName', - PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '/platform/default/public.key', - PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '/platform/default/private.key', +return new PlatformKeyChainRepository([ + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'defaultPlatformKeyId', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'defaultPlatformKeyName', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '/platform/default/public.key', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '/platform/default/private.key', + ] ] ); diff --git a/migrations/Version202402271423013774_taoLti.php b/migrations/Version202402271423013774_taoLti.php new file mode 100644 index 00000000..a52b0ca6 --- /dev/null +++ b/migrations/Version202402271423013774_taoLti.php @@ -0,0 +1,34 @@ +getServiceLocator()->get(PlatformKeyChainRepository::SERVICE_ID); + $options = $platformKeyChainRepository->getOptions(); + $platformKeyChainRepository->setOptions([$options]); + $this->getServiceLocator()->register(PlatformKeyChainRepository::SERVICE_ID, $platformKeyChainRepository); + } + + public function down(Schema $schema): void + { + $platformKeyChainRepository = $this->getServiceLocator()->get(PlatformKeyChainRepository::SERVICE_ID); + $options = $platformKeyChainRepository->getOptions(); + $platformKeyChainRepository->setOptions(reset($options)); + $this->getServiceLocator()->register(PlatformKeyChainRepository::SERVICE_ID, $platformKeyChainRepository); + } +} diff --git a/models/classes/Platform/Service/CachedKeyChainGenerator.php b/models/classes/Platform/Service/CachedKeyChainGenerator.php index dc7a3747..afcb49a1 100644 --- a/models/classes/Platform/Service/CachedKeyChainGenerator.php +++ b/models/classes/Platform/Service/CachedKeyChainGenerator.php @@ -36,7 +36,7 @@ class CachedKeyChainGenerator extends ConfigurableService implements KeyChainGen public function generate(): KeyChainInterface { $keyChain = $this->getKeyChainGenerator()->generate(); - $this->getKeyChainRepository()->save($keyChain); + $this->getKeyChainRepository()->saveDefaultKeyChain($keyChain); $this->invalidateKeyChain($keyChain); $this->invalidateJwks(); diff --git a/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepository.php index 0b80f8fd..e8aa586e 100644 --- a/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepository.php @@ -46,20 +46,19 @@ class CachedPlatformKeyChainRepository extends ConfigurableService implements Ke * @throws InvalidArgumentException * @throws ErrorException */ - public function save(KeyChainInterface $keyChain): void + public function saveDefaultKeyChain(KeyChainInterface $keyChain): void { $this->setKeys( $keyChain, $keyChain->getIdentifier() ); - $this->getPlatformKeyChainRepository()->save($keyChain); + $this->getPlatformKeyChainRepository()->saveDefaultKeyChain($keyChain); } public function find(string $identifier): ?KeyChainInterface { if ($this->exists($identifier)) { - //TODO: Needs to be refactor if we have multiple key chains $rawKeys = $this->getCacheService()->getMultiple( [ sprintf(self::PRIVATE_PATTERN, $identifier), @@ -93,7 +92,6 @@ public function findAll(KeyChainQuery $query): KeyChainCollection } if ($this->exists($query->getIdentifier())) { - //TODO: Needs to be refactor if we have multiple key chains $rawKeys = $this->getCacheService()->getMultiple( [ sprintf(self::PRIVATE_PATTERN, $query->getIdentifier()), diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index a2e64e85..753ad22e 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -48,26 +48,17 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain /** * @throws ErrorException */ - public function save(KeyChainInterface $keyChain): void + public function saveDefaultKeyChain(KeyChainInterface $keyChain): void { - $isKeyFound = false; + $configs = $this->findConfiguration($this->getDefaultKeyId()); - $options = $this->getOptions(); - foreach ($options as $configs) { - $id = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; - - if ($id === $keyChain->getIdentifier()) { - $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; - $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; - $isKeyFound = true; - - break; - } - } - if (!$isKeyFound) { + if (empty($configs)) { throw new ErrorException('Impossible to write LTI keys. Configuration not found'); } + $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $isPublicKeySaved = $this->getFileSystem() ->put( ltrim($publicKey, DIRECTORY_SEPARATOR), @@ -96,27 +87,14 @@ public function getDefaultKeyId(): string */ public function find(string $identifier): ?KeyChainInterface { - $isKeyFound = false; - $options = $this->getOptions(); - foreach ($options as $configs) { - $defaultKeyId = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; - - if ($defaultKeyId === $identifier) { - $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; - $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; - $keyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; - $isKeyFound = true; - - break; - } - } + $configs = $this->findConfiguration($identifier); - if (!$isKeyFound) { + if (empty($configs)) { return null; } - $publicKey = $this->getFileSystem()->read($publicKey); - $privateKey = $this->getFileSystem()->read($privateKey); + $publicKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null); + $privateKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null); if ($publicKey === false || $privateKey === false) { throw new ErrorException('Impossible to read LTI keys'); @@ -124,7 +102,7 @@ public function find(string $identifier): ?KeyChainInterface return new KeyChain( $this->getDefaultKeyId(), - $keyName, + $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null, new Key($publicKey), new Key($privateKey) ); @@ -177,4 +155,20 @@ private function getFileSystem(): FilesystemInterface return $fileSystemService->getFileSystem(self::FILE_SYSTEM_ID); } + + /** + * @param string $identifier + * @return array|null + */ + protected function findConfiguration(string $identifier): ?array + { + $options = $this->getOptions(); + foreach ($options as $configs) { + if ($configs[self::OPTION_DEFAULT_KEY_ID] === $identifier) { + return $configs; + } + } + + return null; + } } diff --git a/test/unit/models/classes/Platform/Service/CachedKeyChainGeneratorTest.php b/test/unit/models/classes/Platform/Service/CachedKeyChainGeneratorTest.php index c2251735..b1cea4d2 100644 --- a/test/unit/models/classes/Platform/Service/CachedKeyChainGeneratorTest.php +++ b/test/unit/models/classes/Platform/Service/CachedKeyChainGeneratorTest.php @@ -69,7 +69,7 @@ public function testGenerate(): void $this->platformKeyChainRepositoryMock ->expects($this->once()) - ->method('save'); + ->method('saveDefaultKeyChain'); $this->simpleCacheMock ->expects($this->exactly(3)) diff --git a/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php index 586a4b12..e2529db7 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php @@ -100,9 +100,9 @@ public function testSave(): void $this->platformKeyChainRepository ->expects($this->once()) - ->method('save'); + ->method('saveDefaultKeyChain'); - $this->subject->save($keyChain); + $this->subject->saveDefaultKeyChain($keyChain); } public function testFindWhenCacheEmpty(): void diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 03d64010..96940e3a 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -27,11 +27,14 @@ use OAT\Library\Lti1p3Core\Security\Key\Key; use OAT\Library\Lti1p3Core\Security\Key\KeyChain; use OAT\Library\Lti1p3Core\Security\Key\KeyChainInterface; +use OAT\Library\Lti1p3Core\Security\Key\KeyInterface; use oat\oatbox\filesystem\FileSystem; use oat\oatbox\filesystem\FileSystemService; +use oat\tao\model\security\Business\Domain\Key\KeyChainQuery; use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use oat\tao\model\security\Business\Domain\Key\Key as TaoKey; class PlatformKeyChainRepositoryTest extends TestCase { @@ -81,17 +84,32 @@ public function testFind(): void $keyChain = $this->subject->find('keyId'); $this->assertInstanceOf(KeyChainInterface::class, $keyChain); - $this->assertEquals( - $keyChain = new KeyChain( - 'keyId', - 'keyName', - new Key('publicKey'), - new Key('privateKey') - ), - $keyChain - ); + $this->assertEquals('keyId', $keyChain->getIdentifier()); + $this->assertEquals('keyName', $keyChain->getKeySetName()); + $this->assertInstanceOf(KeyInterface::class, $keyChain->getPublicKey()); + $this->assertInstanceOf(KeyInterface::class, $keyChain->getPrivateKey()); } + public function testFindAll(): void + { + $this->fileSystem + ->method('read') + ->willReturnOnConsecutiveCalls( + 'publicKey', + 'privateKey' + ); + + $keyChains = $this->subject->findAll(new KeyChainQuery())->getKeyChains(); + + $this->assertIsArray($keyChains); + $keyChain = $keyChains[0]; + $this->assertEquals('keyId', $keyChain->getIdentifier()); + $this->assertEquals('keyName', $keyChain->getName()); + $this->assertInstanceOf(TaoKey::class, $keyChain->getPublicKey()); + $this->assertInstanceOf(TaoKey::class, $keyChain->getPrivateKey()); + } + + public function testFindFails(): void { $this->fileSystem @@ -103,29 +121,29 @@ public function testFindFails(): void $this->assertNull($keyChain); } - public function testSave(): void + public function testSaveDefaultKeyChain(): void { $this->fileSystem ->method('put') ->willReturn(true); - $this->subject->save( - new KeyChain('', '', new Key(''), new Key('')) + $this->subject->saveDefaultKeyChain( + new KeyChain('keyId', '', new Key(''), new Key('')) ); $this->expectNotToPerformAssertions(); } - public function testSaveFails(): void + public function testSaveDefaultKeyChainFails(): void { $this->fileSystem ->method('put') ->willReturn(false); $this->expectException(ErrorException::class); - $this->expectExceptionMessage('Impossible to write LTI keys'); + $this->expectExceptionMessage('Impossible to write LTI keys. Configuration not found'); - $this->subject->save(new KeyChain('', '', new Key(''), new Key(''))); + $this->subject->saveDefaultKeyChain(new KeyChain('', '', new Key(''), new Key(''))); } public function testGetDefaultKeyId(): void From 3ebcc0c59c8e7baf11a4f8ff79255d3638a49fdd Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 18:20:02 +0200 Subject: [PATCH 03/12] feat: NCCER publish to two solar tenants --- .../DataAccess/Repository/PlatformKeyChainRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 96940e3a..106ed7f0 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -141,7 +141,7 @@ public function testSaveDefaultKeyChainFails(): void ->willReturn(false); $this->expectException(ErrorException::class); - $this->expectExceptionMessage('Impossible to write LTI keys. Configuration not found'); + $this->expectExceptionMessage('Impossible to write LTI keys'); $this->subject->saveDefaultKeyChain(new KeyChain('', '', new Key(''), new Key(''))); } From 680f3811949ffbc27d66917a3bc176c6d2797101 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 18:31:46 +0200 Subject: [PATCH 04/12] feat: NCCER publish to two solar tenants --- .../Exception/PlatformKeyChainException.php | 27 +++++++++++++++++++ .../Repository/PlatformKeyChainRepository.php | 18 ++++++------- .../PlatformKeyChainRepositoryTest.php | 4 +-- 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 models/classes/Exception/PlatformKeyChainException.php diff --git a/models/classes/Exception/PlatformKeyChainException.php b/models/classes/Exception/PlatformKeyChainException.php new file mode 100644 index 00000000..aa1832ad --- /dev/null +++ b/models/classes/Exception/PlatformKeyChainException.php @@ -0,0 +1,27 @@ +findConfiguration($this->getDefaultKeyId()); if (empty($configs)) { - throw new ErrorException('Impossible to write LTI keys. Configuration not found'); + throw new PlatformKeyChainException('Impossible to write LTI keys. Configuration not found'); } $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; @@ -72,7 +70,7 @@ public function saveDefaultKeyChain(KeyChainInterface $keyChain): void ); if (!$isPublicKeySaved || !$isPrivateKeySaved) { - throw new ErrorException('Impossible to write LTI keys'); + throw new PlatformKeyChainException('Impossible to write LTI keys'); } } @@ -97,7 +95,7 @@ public function find(string $identifier): ?KeyChainInterface $privateKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null); if ($publicKey === false || $privateKey === false) { - throw new ErrorException('Impossible to read LTI keys'); + throw new PlatformKeyChainException('Impossible to read LTI keys'); } return new KeyChain( @@ -132,7 +130,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection } if (empty($keyChains)) { - throw new ErrorException('Impossible to read LTI keys'); + throw new PlatformKeyChainException('Impossible to read LTI keys'); } return new KeyChainCollection($keyChains); diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 106ed7f0..3798b788 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -22,7 +22,6 @@ namespace oat\taoLti\test\unit\models\classes\Security\DataAccess\Repository; -use ErrorException; use oat\generis\test\ServiceManagerMockTrait; use OAT\Library\Lti1p3Core\Security\Key\Key; use OAT\Library\Lti1p3Core\Security\Key\KeyChain; @@ -31,6 +30,7 @@ use oat\oatbox\filesystem\FileSystem; use oat\oatbox\filesystem\FileSystemService; use oat\tao\model\security\Business\Domain\Key\KeyChainQuery; +use oat\taoLti\models\classes\Exception\PlatformKeyChainException; use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -140,7 +140,7 @@ public function testSaveDefaultKeyChainFails(): void ->method('put') ->willReturn(false); - $this->expectException(ErrorException::class); + $this->expectException(PlatformKeyChainException::class); $this->expectExceptionMessage('Impossible to write LTI keys'); $this->subject->saveDefaultKeyChain(new KeyChain('', '', new Key(''), new Key(''))); From b45f4c06932a6021da2e92f6167537bdf4e468a1 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 19:05:29 +0200 Subject: [PATCH 05/12] feat: NCCER publish to two solar tenants --- config/default/PlatformKeyChainRepository.conf.php | 13 ++++++------- .../Repository/PlatformKeyChainRepository.php | 1 - .../Repository/PlatformKeyChainRepositoryTest.php | 13 ++++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/config/default/PlatformKeyChainRepository.conf.php b/config/default/PlatformKeyChainRepository.conf.php index 173eed4f..c09b5c73 100644 --- a/config/default/PlatformKeyChainRepository.conf.php +++ b/config/default/PlatformKeyChainRepository.conf.php @@ -3,11 +3,10 @@ use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; return new PlatformKeyChainRepository([ - [ - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'defaultPlatformKeyId', - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'defaultPlatformKeyName', - PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '/platform/default/public.key', - PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '/platform/default/private.key', - ] + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'defaultPlatformKeyId', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'defaultPlatformKeyName', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '/platform/default/public.key', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '/platform/default/private.key', ] -); +]); diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 491bc404..047bb21d 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -126,7 +126,6 @@ public function findAll(KeyChainQuery $query): KeyChainCollection new TaoKey($privateKey) ); } - } if (empty($keyChains)) { diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 3798b788..2ad001f3 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -55,14 +55,13 @@ public function setUp(): void ->willReturn($this->fileSystem); $this->subject = new PlatformKeyChainRepository([ - [ - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId', - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', - PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', - PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', - ] + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', ] - ); + ]); $this->subject->setServiceLocator( $this->getServiceManagerMock( [ From 853d4481c9bf58f3dd834f932b4e391ad518429a Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Tue, 27 Feb 2024 20:02:43 +0200 Subject: [PATCH 06/12] feat: NCCER publish to two solar tenants --- .../Repository/PlatformKeyChainRepository.php | 4 ++-- .../Repository/PlatformJwksRepositoryTest.php | 2 +- .../PlatformKeyChainRepositoryTest.php | 21 +++++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 047bb21d..426bf7d1 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -99,7 +99,7 @@ public function find(string $identifier): ?KeyChainInterface } return new KeyChain( - $this->getDefaultKeyId(), + $configs[self::OPTION_DEFAULT_KEY_ID] ?? null, $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null, new Key($publicKey), new Key($privateKey) @@ -119,7 +119,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection $publicKey = $this->getFileSystem()->read($publicKey); $privateKey = $this->getFileSystem()->read($privateKey); - $keyChains = new TaoKeyChain( + $keyChains[] = new TaoKeyChain( $defaultKeyId, $defaultKeyName, new TaoKey($publicKey), diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php index a2e58854..388400c9 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php @@ -63,7 +63,7 @@ public function setUp(): void public function testFind(): void { $keyChain = new KeyChain('id', 'name', new Key('123456'), new Key('654321')); - $collection = new KeyChainCollection(...[$keyChain]); + $collection = new KeyChainCollection([$keyChain]); $this->keyChainRepository ->method('findAll') diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index 2ad001f3..a176acdf 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -60,6 +60,12 @@ public function setUp(): void PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', + ], + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId2', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName2', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', ] ]); $this->subject->setServiceLocator( @@ -80,11 +86,11 @@ public function testFind(): void 'privateKey' ); - $keyChain = $this->subject->find('keyId'); + $keyChain = $this->subject->find('keyId2'); $this->assertInstanceOf(KeyChainInterface::class, $keyChain); - $this->assertEquals('keyId', $keyChain->getIdentifier()); - $this->assertEquals('keyName', $keyChain->getKeySetName()); + $this->assertEquals('keyId2', $keyChain->getIdentifier()); + $this->assertEquals('keyName2', $keyChain->getKeySetName()); $this->assertInstanceOf(KeyInterface::class, $keyChain->getPublicKey()); $this->assertInstanceOf(KeyInterface::class, $keyChain->getPrivateKey()); } @@ -94,6 +100,8 @@ public function testFindAll(): void $this->fileSystem ->method('read') ->willReturnOnConsecutiveCalls( + 'publicKey', + 'privateKey', 'publicKey', 'privateKey' ); @@ -101,9 +109,10 @@ public function testFindAll(): void $keyChains = $this->subject->findAll(new KeyChainQuery())->getKeyChains(); $this->assertIsArray($keyChains); - $keyChain = $keyChains[0]; - $this->assertEquals('keyId', $keyChain->getIdentifier()); - $this->assertEquals('keyName', $keyChain->getName()); + $this->assertCount(2, $keyChains); + $keyChain = $keyChains[1]; + $this->assertEquals('keyId2', $keyChain->getIdentifier()); + $this->assertEquals('keyName2', $keyChain->getName()); $this->assertInstanceOf(TaoKey::class, $keyChain->getPublicKey()); $this->assertInstanceOf(TaoKey::class, $keyChain->getPrivateKey()); } From 3eed03fcb2c6a1fd04910a91475b617cb4d1e203 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Wed, 28 Feb 2024 16:02:22 +0200 Subject: [PATCH 07/12] feat: NCCER publish to two solar tenants --- .../Repository/PlatformKeyChainRepository.php | 43 ++++++++++++------- .../PlatformKeyChainRepositoryTest.php | 23 ++++++++-- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 426bf7d1..15f751f4 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -56,18 +56,22 @@ public function saveDefaultKeyChain(KeyChainInterface $keyChain): void $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $isPublicKeySaved = null; + $isPrivateKeySaved = null; + + if ($publicKey !== null && $privateKey !== null) { + $isPublicKeySaved = $this->getFileSystem() + ->put( + ltrim($publicKey, DIRECTORY_SEPARATOR), + $keyChain->getPublicKey()->getContent() + ); - $isPublicKeySaved = $this->getFileSystem() - ->put( - ltrim($publicKey, DIRECTORY_SEPARATOR), - $keyChain->getPublicKey()->getContent() - ); - - $isPrivateKeySaved = $this->getFileSystem() - ->put( - ltrim($privateKey, DIRECTORY_SEPARATOR), - $keyChain->getPrivateKey()->getContent() - ); + $isPrivateKeySaved = $this->getFileSystem() + ->put( + ltrim($privateKey, DIRECTORY_SEPARATOR), + $keyChain->getPrivateKey()->getContent() + ); + } if (!$isPublicKeySaved || !$isPrivateKeySaved) { throw new PlatformKeyChainException('Impossible to write LTI keys'); @@ -91,6 +95,13 @@ public function find(string $identifier): ?KeyChainInterface return null; } + $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + + if (!$publicKeyPath || !$privateKeyPath) { + throw new PlatformKeyChainException('The key path is not defined'); + } + $publicKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null); $privateKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null); @@ -112,12 +123,12 @@ public function findAll(KeyChainQuery $query): KeyChainCollection foreach ($options as $configs) { $defaultKeyId = $configs[self::OPTION_DEFAULT_KEY_ID] ?? null; $defaultKeyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; - $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; - $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; - if ($defaultKeyId) { - $publicKey = $this->getFileSystem()->read($publicKey); - $privateKey = $this->getFileSystem()->read($privateKey); + if ($defaultKeyId && $publicKeyPath && $privateKeyPath) { + $publicKey = $this->getFileSystem()->read($publicKeyPath); + $privateKey = $this->getFileSystem()->read($privateKeyPath); $keyChains[] = new TaoKeyChain( $defaultKeyId, diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php index a176acdf..e16b5988 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepositoryTest.php @@ -58,12 +58,18 @@ public function setUp(): void [ PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId', PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName', - PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', - PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => 'publicPath', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => 'privatePath', ], [ PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId2', PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName2', + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => 'publicPath', + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => 'privatePath', + ], + [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => 'keyId3', + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => 'keyName3', PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => '', PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => '', ] @@ -103,7 +109,9 @@ public function testFindAll(): void 'publicKey', 'privateKey', 'publicKey', - 'privateKey' + 'privateKey', + '', + '' ); $keyChains = $this->subject->findAll(new KeyChainQuery())->getKeyChains(); @@ -117,7 +125,6 @@ public function testFindAll(): void $this->assertInstanceOf(TaoKey::class, $keyChain->getPrivateKey()); } - public function testFindFails(): void { $this->fileSystem @@ -129,6 +136,14 @@ public function testFindFails(): void $this->assertNull($keyChain); } + public function testFindWithEmptyPathFails(): void + { + $this->expectException(PlatformKeyChainException::class); + $this->expectExceptionMessage('The key path is not defined'); + + $this->subject->find('keyId3'); + } + public function testSaveDefaultKeyChain(): void { $this->fileSystem From 961183e182c648478f4bd09a5258c6f159df8a62 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Wed, 28 Feb 2024 19:36:55 +0200 Subject: [PATCH 08/12] feat: NCCER publish to two solar tenants --- .../Service/CachedKeyChainGenerator.php | 21 +++- .../Service/KeyChainGeneratorInterface.php | 2 +- .../Service/OpenSslKeyChainGenerator.php | 10 +- .../Repository/PlatformKeyChainRepository.php | 14 ++- scripts/tools/GenerateKeys.php | 113 ++++++++++++++++++ 5 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 scripts/tools/GenerateKeys.php diff --git a/models/classes/Platform/Service/CachedKeyChainGenerator.php b/models/classes/Platform/Service/CachedKeyChainGenerator.php index afcb49a1..2c0ff35b 100644 --- a/models/classes/Platform/Service/CachedKeyChainGenerator.php +++ b/models/classes/Platform/Service/CachedKeyChainGenerator.php @@ -23,7 +23,6 @@ namespace oat\taoLti\models\classes\Platform\Service; use OAT\Library\Lti1p3Core\Security\Key\KeyChainInterface; -use OAT\Library\Lti1p3Core\Security\Key\KeyChainRepositoryInterface; use oat\oatbox\cache\SimpleCache; use oat\oatbox\service\ConfigurableService; use oat\taoLti\models\classes\Security\DataAccess\Repository\CachedPlatformJwksRepository; @@ -33,15 +32,25 @@ class CachedKeyChainGenerator extends ConfigurableService implements KeyChainGeneratorInterface { - public function generate(): KeyChainInterface + + public function generate( + string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID_VALUE, + string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME_VALUE + ): KeyChainInterface { + $keyChain = $this->getKeyChainGenerator()->generate($id, $name); + $this->save($keyChain); + + return $keyChain; + } + + private function save(KeyChainInterface $keyChain): bool { - $keyChain = $this->getKeyChainGenerator()->generate(); - $this->getKeyChainRepository()->saveDefaultKeyChain($keyChain); + $this->getKeyChainRepository()->saveKeyChain($keyChain); $this->invalidateKeyChain($keyChain); $this->invalidateJwks(); - return $keyChain; + return true; } private function invalidateKeyChain(KeyChainInterface $keyChain): void @@ -65,7 +74,7 @@ private function getKeyChainGenerator(): KeyChainGeneratorInterface return $this->getServiceLocator()->get(OpenSslKeyChainGenerator::class); } - private function getKeyChainRepository(): KeyChainRepositoryInterface + private function getKeyChainRepository(): PlatformKeyChainRepository { return $this->getServiceLocator()->get(PlatformKeyChainRepository::class); } diff --git a/models/classes/Platform/Service/KeyChainGeneratorInterface.php b/models/classes/Platform/Service/KeyChainGeneratorInterface.php index 0610d5a3..549e6d98 100644 --- a/models/classes/Platform/Service/KeyChainGeneratorInterface.php +++ b/models/classes/Platform/Service/KeyChainGeneratorInterface.php @@ -28,5 +28,5 @@ interface KeyChainGeneratorInterface { public const OPTION_DATA_STORE = 'sslConfig'; - public function generate(): KeyChainInterface; + public function generate(string $id, string $name): KeyChainInterface; } diff --git a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php index 4cb938e6..ad8cb27c 100644 --- a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php +++ b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php @@ -30,15 +30,17 @@ class OpenSslKeyChainGenerator extends ConfigurableService implements KeyChainGeneratorInterface { - public function generate(): KeyChainInterface - { + public function generate( + string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, + string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME + ): KeyChainInterface { $resource = openssl_pkey_new($this->getOption(self::OPTION_DATA_STORE)); openssl_pkey_export($resource, $privateKey); $publicKey = openssl_pkey_get_details($resource); return new KeyChain( - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, - PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME, + $id, + $name, new Key($publicKey['key']), new Key($privateKey) ); diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 15f751f4..93da094a 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -40,7 +40,9 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain { public const SERVICE_ID = 'taoLti/PlatformKeyChainRepository'; public const OPTION_DEFAULT_KEY_ID = 'defaultKeyId'; + public const OPTION_DEFAULT_KEY_ID_VALUE = 'defaultPlatformKeyId'; public const OPTION_DEFAULT_KEY_NAME = 'defaultKeyName'; + public const OPTION_DEFAULT_KEY_NAME_VALUE = 'defaultPlatformKeyName'; public const OPTION_DEFAULT_PUBLIC_KEY_PATH = 'defaultPublicKeyPath'; public const OPTION_DEFAULT_PRIVATE_KEY_PATH = 'defaultPrivateKeyPath'; public const FILE_SYSTEM_ID = 'ltiKeyChain'; @@ -48,7 +50,17 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain public function saveDefaultKeyChain(KeyChainInterface $keyChain): void { - $configs = $this->findConfiguration($this->getDefaultKeyId()); + $this->save($keyChain, $this->getDefaultKeyId()); + } + + public function saveKeyChain(KeyChainInterface $keyChain): void + { + $this->save($keyChain, $keyChain->getIdentifier()); + } + + protected function save(KeyChainInterface $keyChain, string $identifier): void + { + $configs = $this->findConfiguration($identifier); if (empty($configs)) { throw new PlatformKeyChainException('Impossible to write LTI keys. Configuration not found'); diff --git a/scripts/tools/GenerateKeys.php b/scripts/tools/GenerateKeys.php new file mode 100644 index 00000000..6bbb2664 --- /dev/null +++ b/scripts/tools/GenerateKeys.php @@ -0,0 +1,113 @@ + [ + 'prefix' => 'id', + 'longPrefix' => 'key_id', + 'description' => 'Lti Platform key chain id', + 'required' => true, + 'cast' => 'string' + ], + 'key_name' => [ + 'prefix' => 'kn', + 'longPrefix' => 'key_name', + 'description' => 'Lti Platform key chain name', + 'required' => true, + 'cast' => 'string' + ], + 'public_key_path' => [ + 'prefix' => 'pkp', + 'longPrefix' => 'public_key_path', + 'description' => 'Lti Platform public key path', + 'required' => true, + 'cast' => 'string' + ], + 'private_key_path' => [ + 'prefix' => 'kp', + 'longPrefix' => 'private_key_path', + 'description' => 'Lti Platform private key path', + 'required' => true, + 'cast' => 'string' + ], + ]; + } + + protected function provideDescription() + { + return 'Script to create a LTI Platform Key Chain'; + } + + protected function provideUsage() + { + return [ + 'prefix' => 'h', + 'longPrefix' => 'help', + 'description' => 'Prints the help.' + ]; + } + + protected function run() + { + $keyId = $this->getOption('key_id'); + $keyName = $this->getOption('key_name'); + $publicKeyPath = $this->getOption('public_key_path'); + $privateKeyPath = $this->getOption('private_key_path'); + + if (empty($keyId) || empty($keyName) || empty($publicKeyPath) || empty($privateKeyPath)) { + return Report::createError( + 'Not all required arguments were provided. Try to run the script with -h option' + ); + } + $platformKeyChainRepository = $this->getServiceLocator()->get(PlatformKeyChainRepository::SERVICE_ID); + $options = $platformKeyChainRepository->getOptions(); + $options[] = [ + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => $keyId, + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => $keyName, + PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => $publicKeyPath, + PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => $privateKeyPath, + ]; + $platformKeyChainRepository->setOptions($options); + $this->getServiceLocator()->register(PlatformKeyChainRepository::SERVICE_ID, $platformKeyChainRepository); + + /** @var CachedKeyChainGenerator $cachedKeyChainGenerator */ + $cachedKeyChainGenerator = $this->getServiceLocator()->get(CachedKeyChainGenerator::class); + $cachedKeyChainGenerator->generate($keyId, $keyName); + + return Report::createSuccess('LTI Platform Key Chain generated successfully!'); + } +} From fc2d30d05abfc800410b8c24c375a0c1fd002054 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Thu, 29 Feb 2024 11:09:02 +0200 Subject: [PATCH 09/12] feat: NCCER publish to two solar tenants --- .../Repository/PlatformKeyChainRepository.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 93da094a..ec62128f 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -66,21 +66,21 @@ protected function save(KeyChainInterface $keyChain, string $identifier): void throw new PlatformKeyChainException('Impossible to write LTI keys. Configuration not found'); } - $publicKey = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; - $privateKey = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; + $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; $isPublicKeySaved = null; $isPrivateKeySaved = null; - if ($publicKey !== null && $privateKey !== null) { + if ($publicKeyPath !== null && $privateKeyPath !== null) { $isPublicKeySaved = $this->getFileSystem() ->put( - ltrim($publicKey, DIRECTORY_SEPARATOR), + ltrim($publicKeyPath, DIRECTORY_SEPARATOR), $keyChain->getPublicKey()->getContent() ); $isPrivateKeySaved = $this->getFileSystem() ->put( - ltrim($privateKey, DIRECTORY_SEPARATOR), + ltrim($privateKeyPath, DIRECTORY_SEPARATOR), $keyChain->getPrivateKey()->getContent() ); } @@ -114,8 +114,8 @@ public function find(string $identifier): ?KeyChainInterface throw new PlatformKeyChainException('The key path is not defined'); } - $publicKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null); - $privateKey = $this->getFileSystem()->read($configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null); + $publicKey = $this->getFileSystem()->read($publicKeyPath); + $privateKey = $this->getFileSystem()->read($privateKeyPath); if ($publicKey === false || $privateKey === false) { throw new PlatformKeyChainException('Impossible to read LTI keys'); From 0712dcce3de96d54c9195436aad83a494077cb5a Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Fri, 1 Mar 2024 17:10:54 +0200 Subject: [PATCH 10/12] feat: NCCER publish to two solar tenants --- .../Service/CachedKeyChainGenerator.php | 5 +++-- .../Service/KeyChainGeneratorInterface.php | 2 +- .../Service/OpenSslKeyChainGenerator.php | 5 +++-- .../Repository/PlatformKeyChainRepository.php | 9 ++++++--- scripts/tools/GenerateKeys.php | 17 ++++++++++++++++- .../Repository/PlatformJwksRepositoryTest.php | 2 +- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/models/classes/Platform/Service/CachedKeyChainGenerator.php b/models/classes/Platform/Service/CachedKeyChainGenerator.php index 2c0ff35b..75c5dd0c 100644 --- a/models/classes/Platform/Service/CachedKeyChainGenerator.php +++ b/models/classes/Platform/Service/CachedKeyChainGenerator.php @@ -35,9 +35,10 @@ class CachedKeyChainGenerator extends ConfigurableService implements KeyChainGen public function generate( string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID_VALUE, - string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME_VALUE + string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME_VALUE, + ?string $keyPassword = null ): KeyChainInterface { - $keyChain = $this->getKeyChainGenerator()->generate($id, $name); + $keyChain = $this->getKeyChainGenerator()->generate($id, $name, $keyPassword); $this->save($keyChain); return $keyChain; diff --git a/models/classes/Platform/Service/KeyChainGeneratorInterface.php b/models/classes/Platform/Service/KeyChainGeneratorInterface.php index 549e6d98..343b709b 100644 --- a/models/classes/Platform/Service/KeyChainGeneratorInterface.php +++ b/models/classes/Platform/Service/KeyChainGeneratorInterface.php @@ -28,5 +28,5 @@ interface KeyChainGeneratorInterface { public const OPTION_DATA_STORE = 'sslConfig'; - public function generate(string $id, string $name): KeyChainInterface; + public function generate(string $id, string $name, ?string $keyPassword): KeyChainInterface; } diff --git a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php index ad8cb27c..8fe31b65 100644 --- a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php +++ b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php @@ -32,7 +32,8 @@ class OpenSslKeyChainGenerator extends ConfigurableService implements KeyChainGe { public function generate( string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, - string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME + string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME, + ?string $keyPassword = null ): KeyChainInterface { $resource = openssl_pkey_new($this->getOption(self::OPTION_DATA_STORE)); openssl_pkey_export($resource, $privateKey); @@ -42,7 +43,7 @@ public function generate( $id, $name, new Key($publicKey['key']), - new Key($privateKey) + new Key($privateKey, $keyPassword) ); } } diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index ec62128f..3c737c9d 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -45,6 +45,7 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain public const OPTION_DEFAULT_KEY_NAME_VALUE = 'defaultPlatformKeyName'; public const OPTION_DEFAULT_PUBLIC_KEY_PATH = 'defaultPublicKeyPath'; public const OPTION_DEFAULT_PRIVATE_KEY_PATH = 'defaultPrivateKeyPath'; + public const OPTION_DEFAULT_PRIVATE_KEY_PASSWORD = 'defaultPrivateKeyPassword'; public const FILE_SYSTEM_ID = 'ltiKeyChain'; @@ -109,6 +110,7 @@ public function find(string $identifier): ?KeyChainInterface $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] ?? null; if (!$publicKeyPath || !$privateKeyPath) { throw new PlatformKeyChainException('The key path is not defined'); @@ -125,7 +127,7 @@ public function find(string $identifier): ?KeyChainInterface $configs[self::OPTION_DEFAULT_KEY_ID] ?? null, $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null, new Key($publicKey), - new Key($privateKey) + new Key($privateKey, $privateKeyPassword) ); } @@ -137,6 +139,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection $defaultKeyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; + $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] ?? null; if ($defaultKeyId && $publicKeyPath && $privateKeyPath) { $publicKey = $this->getFileSystem()->read($publicKeyPath); @@ -146,7 +149,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection $defaultKeyId, $defaultKeyName, new TaoKey($publicKey), - new TaoKey($privateKey) + new TaoKey($privateKey, $privateKeyPassword) ); } } @@ -155,7 +158,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection throw new PlatformKeyChainException('Impossible to read LTI keys'); } - return new KeyChainCollection($keyChains); + return new KeyChainCollection(...$keyChains); } diff --git a/scripts/tools/GenerateKeys.php b/scripts/tools/GenerateKeys.php index 6bbb2664..2674098a 100644 --- a/scripts/tools/GenerateKeys.php +++ b/scripts/tools/GenerateKeys.php @@ -24,6 +24,7 @@ use oat\oatbox\extension\script\ScriptAction; use oat\oatbox\reporting\Report; +use oat\taoLti\models\classes\Platform\Service\OpenSslKeyChainGenerator; use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; use oat\taoLti\models\classes\Platform\Service\CachedKeyChainGenerator; @@ -64,6 +65,13 @@ protected function provideOptions() 'required' => true, 'cast' => 'string' ], + 'private_key_password' => [ + 'prefix' => 'kpp', + 'longPrefix' => 'private_key_password', + 'description' => 'Lti Platform private key password', + 'required' => false, + 'cast' => 'string' + ], ]; } @@ -87,6 +95,7 @@ protected function run() $keyName = $this->getOption('key_name'); $publicKeyPath = $this->getOption('public_key_path'); $privateKeyPath = $this->getOption('private_key_path'); + $privateKeyPassword = $this->getOption('private_key_password'); if (empty($keyId) || empty($keyName) || empty($publicKeyPath) || empty($privateKeyPath)) { return Report::createError( @@ -95,12 +104,18 @@ protected function run() } $platformKeyChainRepository = $this->getServiceLocator()->get(PlatformKeyChainRepository::SERVICE_ID); $options = $platformKeyChainRepository->getOptions(); - $options[] = [ + $option = [ PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID => $keyId, PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME => $keyName, PlatformKeyChainRepository::OPTION_DEFAULT_PUBLIC_KEY_PATH => $publicKeyPath, PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => $privateKeyPath, ]; + + if (!empty($privateKeyPassword)) { + $option[PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] = $privateKeyPassword; + } + + $options[] = $option; $platformKeyChainRepository->setOptions($options); $this->getServiceLocator()->register(PlatformKeyChainRepository::SERVICE_ID, $platformKeyChainRepository); diff --git a/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php index 388400c9..898d7cad 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/PlatformJwksRepositoryTest.php @@ -63,7 +63,7 @@ public function setUp(): void public function testFind(): void { $keyChain = new KeyChain('id', 'name', new Key('123456'), new Key('654321')); - $collection = new KeyChainCollection([$keyChain]); + $collection = new KeyChainCollection($keyChain); $this->keyChainRepository ->method('findAll') From 4dc2cf342273f62303a77d74771f6d152ccf4fa4 Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Fri, 1 Mar 2024 17:28:46 +0200 Subject: [PATCH 11/12] feat: NCCER publish to two solar tenants --- .../DataAccess/Repository/PlatformKeyChainRepository.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 3c737c9d..860a9b33 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -97,9 +97,6 @@ public function getDefaultKeyId(): string return reset($options)[self::OPTION_DEFAULT_KEY_ID] ?? ''; } - /** - * @throws common_exception_NoImplementation - */ public function find(string $identifier): ?KeyChainInterface { $configs = $this->findConfiguration($identifier); From 3b7d390ad512fae11aca6669c97dd4c695575cbc Mon Sep 17 00:00:00 2001 From: Makar Sichevoi Date: Mon, 4 Mar 2024 16:06:42 +0200 Subject: [PATCH 12/12] feat: NCCER publish to two solar tenants --- .../Service/CachedKeyChainGenerator.php | 4 ++-- .../Service/KeyChainGeneratorInterface.php | 2 +- .../Service/OpenSslKeyChainGenerator.php | 6 +++--- .../Repository/PlatformKeyChainRepository.php | 6 +++--- scripts/tools/GenerateKeys.php | 14 +++++++------- .../Platform/Service/KeyChainGeneratorTest.php | 17 +++++++++++++++++ .../CachedPlatformKeyChainRepositoryTest.php | 4 +++- 7 files changed, 36 insertions(+), 17 deletions(-) diff --git a/models/classes/Platform/Service/CachedKeyChainGenerator.php b/models/classes/Platform/Service/CachedKeyChainGenerator.php index 75c5dd0c..48364b98 100644 --- a/models/classes/Platform/Service/CachedKeyChainGenerator.php +++ b/models/classes/Platform/Service/CachedKeyChainGenerator.php @@ -36,9 +36,9 @@ class CachedKeyChainGenerator extends ConfigurableService implements KeyChainGen public function generate( string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID_VALUE, string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME_VALUE, - ?string $keyPassword = null + ?string $passPhrase = null ): KeyChainInterface { - $keyChain = $this->getKeyChainGenerator()->generate($id, $name, $keyPassword); + $keyChain = $this->getKeyChainGenerator()->generate($id, $name, $passPhrase); $this->save($keyChain); return $keyChain; diff --git a/models/classes/Platform/Service/KeyChainGeneratorInterface.php b/models/classes/Platform/Service/KeyChainGeneratorInterface.php index 343b709b..5824eccc 100644 --- a/models/classes/Platform/Service/KeyChainGeneratorInterface.php +++ b/models/classes/Platform/Service/KeyChainGeneratorInterface.php @@ -28,5 +28,5 @@ interface KeyChainGeneratorInterface { public const OPTION_DATA_STORE = 'sslConfig'; - public function generate(string $id, string $name, ?string $keyPassword): KeyChainInterface; + public function generate(string $id, string $name, ?string $passPhrase): KeyChainInterface; } diff --git a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php index 8fe31b65..0e86d723 100644 --- a/models/classes/Platform/Service/OpenSslKeyChainGenerator.php +++ b/models/classes/Platform/Service/OpenSslKeyChainGenerator.php @@ -33,17 +33,17 @@ class OpenSslKeyChainGenerator extends ConfigurableService implements KeyChainGe public function generate( string $id = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, string $name = PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME, - ?string $keyPassword = null + ?string $passPhrase = null ): KeyChainInterface { $resource = openssl_pkey_new($this->getOption(self::OPTION_DATA_STORE)); - openssl_pkey_export($resource, $privateKey); + openssl_pkey_export($resource, $privateKey, $passPhrase); $publicKey = openssl_pkey_get_details($resource); return new KeyChain( $id, $name, new Key($publicKey['key']), - new Key($privateKey, $keyPassword) + new Key($privateKey, $passPhrase) ); } } diff --git a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php index 860a9b33..2fa37b00 100644 --- a/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php +++ b/models/classes/Security/DataAccess/Repository/PlatformKeyChainRepository.php @@ -45,7 +45,7 @@ class PlatformKeyChainRepository extends ConfigurableService implements KeyChain public const OPTION_DEFAULT_KEY_NAME_VALUE = 'defaultPlatformKeyName'; public const OPTION_DEFAULT_PUBLIC_KEY_PATH = 'defaultPublicKeyPath'; public const OPTION_DEFAULT_PRIVATE_KEY_PATH = 'defaultPrivateKeyPath'; - public const OPTION_DEFAULT_PRIVATE_KEY_PASSWORD = 'defaultPrivateKeyPassword'; + public const OPTION_DEFAULT_PRIVATE_KEY_PASSPHRASE = 'defaultPrivateKeyPassphrase'; public const FILE_SYSTEM_ID = 'ltiKeyChain'; @@ -107,7 +107,7 @@ public function find(string $identifier): ?KeyChainInterface $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; - $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] ?? null; + $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSPHRASE] ?? null; if (!$publicKeyPath || !$privateKeyPath) { throw new PlatformKeyChainException('The key path is not defined'); @@ -136,7 +136,7 @@ public function findAll(KeyChainQuery $query): KeyChainCollection $defaultKeyName = $configs[self::OPTION_DEFAULT_KEY_NAME] ?? null; $publicKeyPath = $configs[self::OPTION_DEFAULT_PUBLIC_KEY_PATH] ?? null; $privateKeyPath = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PATH] ?? null; - $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] ?? null; + $privateKeyPassword = $configs[self::OPTION_DEFAULT_PRIVATE_KEY_PASSPHRASE] ?? null; if ($defaultKeyId && $publicKeyPath && $privateKeyPath) { $publicKey = $this->getFileSystem()->read($publicKeyPath); diff --git a/scripts/tools/GenerateKeys.php b/scripts/tools/GenerateKeys.php index 2674098a..abaf4a85 100644 --- a/scripts/tools/GenerateKeys.php +++ b/scripts/tools/GenerateKeys.php @@ -65,10 +65,10 @@ protected function provideOptions() 'required' => true, 'cast' => 'string' ], - 'private_key_password' => [ + 'private_key_passphrase' => [ 'prefix' => 'kpp', - 'longPrefix' => 'private_key_password', - 'description' => 'Lti Platform private key password', + 'longPrefix' => 'private_key_passphrase', + 'description' => 'Lti Platform private key passphrase', 'required' => false, 'cast' => 'string' ], @@ -95,7 +95,7 @@ protected function run() $keyName = $this->getOption('key_name'); $publicKeyPath = $this->getOption('public_key_path'); $privateKeyPath = $this->getOption('private_key_path'); - $privateKeyPassword = $this->getOption('private_key_password'); + $privateKeyPassphrase = $this->getOption('private_key_passphrase'); if (empty($keyId) || empty($keyName) || empty($publicKeyPath) || empty($privateKeyPath)) { return Report::createError( @@ -111,8 +111,8 @@ protected function run() PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PATH => $privateKeyPath, ]; - if (!empty($privateKeyPassword)) { - $option[PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PASSWORD] = $privateKeyPassword; + if (!empty($privateKeyPassphrase)) { + $option[PlatformKeyChainRepository::OPTION_DEFAULT_PRIVATE_KEY_PASSPHRASE] = $privateKeyPassphrase; } $options[] = $option; @@ -121,7 +121,7 @@ protected function run() /** @var CachedKeyChainGenerator $cachedKeyChainGenerator */ $cachedKeyChainGenerator = $this->getServiceLocator()->get(CachedKeyChainGenerator::class); - $cachedKeyChainGenerator->generate($keyId, $keyName); + $cachedKeyChainGenerator->generate($keyId, $keyName, $privateKeyPassphrase); return Report::createSuccess('LTI Platform Key Chain generated successfully!'); } diff --git a/test/unit/models/classes/Platform/Service/KeyChainGeneratorTest.php b/test/unit/models/classes/Platform/Service/KeyChainGeneratorTest.php index 7e4a0d4a..ec56d85b 100644 --- a/test/unit/models/classes/Platform/Service/KeyChainGeneratorTest.php +++ b/test/unit/models/classes/Platform/Service/KeyChainGeneratorTest.php @@ -24,6 +24,7 @@ use oat\generis\test\TestCase; use oat\taoLti\models\classes\Platform\Service\OpenSslKeyChainGenerator; +use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository; class KeyChainGeneratorTest extends TestCase { @@ -44,4 +45,20 @@ public function testGenerate(): void $this->assertStringContainsString('-----BEGIN PUBLIC KEY-----', $result->getPublicKey()->getContent()); $this->assertStringContainsString('-----END PUBLIC KEY-----', $result->getPublicKey()->getContent()); } + + public function testGenerateWithPassphrase(): void + { + $result = $this->subject->generate( + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_ID, + PlatformKeyChainRepository::OPTION_DEFAULT_KEY_NAME, + 'pass' + ); + + $this->assertEquals('pass', $result->getPrivateKey()->getPassPhrase()); + $this->assertEmpty($result->getPublicKey()->getPassPhrase()); + $this->assertStringContainsString('-----BEGIN ENCRYPTED PRIVATE KEY-----', $result->getPrivateKey()->getContent()); + $this->assertStringContainsString('-----END ENCRYPTED PRIVATE KEY-----', $result->getPrivateKey()->getContent()); + $this->assertStringContainsString('-----BEGIN PUBLIC KEY-----', $result->getPublicKey()->getContent()); + $this->assertStringContainsString('-----END PUBLIC KEY-----', $result->getPublicKey()->getContent()); + } } diff --git a/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php b/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php index e2529db7..7b6ae2fc 100644 --- a/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php +++ b/test/unit/models/classes/Security/DataAccess/Repository/CachedPlatformKeyChainRepositoryTest.php @@ -143,7 +143,9 @@ public function testFindWhenCacheEmpty(): void $this->assertSame(self::KEY_CHAIN_ID, $keyChain->getIdentifier()); $this->assertSame('privateKey', $keyChain->getPrivateKey()->getContent()); + $this->assertSame('pass', $keyChain->getPrivateKey()->getPassPhrase()); $this->assertSame('publicKey', $keyChain->getPublicKey()->getContent()); + $this->assertNull($keyChain->getPublicKey()->getPassPhrase()); } public function testFind(): void @@ -187,7 +189,7 @@ private function getKeyChain(): KeyChainInterface self::KEY_CHAIN_ID, self::KEY_CHAIN_NAME, new Key('publicKey'), - new Key('privateKey') + new Key('privateKey', 'pass') ); } }