![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/dev/tests/integration/testsuite/Magento/Framework/Jwt/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Framework\Jwt; use Magento\Framework\Jwt\Claim\ExpirationTime; use Magento\Framework\Jwt\Claim\IssuedAt; use Magento\Framework\Jwt\Claim\Issuer; use Magento\Framework\Jwt\Claim\JwtId; use Magento\Framework\Jwt\Claim\PrivateClaim; use Magento\Framework\Jwt\Claim\Subject; use Magento\Framework\Jwt\Header\Critical; use Magento\Framework\Jwt\Header\KeyId; use Magento\Framework\Jwt\Header\PrivateHeaderParameter; use Magento\Framework\Jwt\Header\PublicHeaderParameter; use Magento\Framework\Jwt\Jwe\Jwe; use Magento\Framework\Jwt\Jwe\JweEncryptionJwks; use Magento\Framework\Jwt\Jwe\JweEncryptionSettingsInterface; use Magento\Framework\Jwt\Jwe\JweHeader; use Magento\Framework\Jwt\Jwe\JweInterface; use Magento\Framework\Jwt\Jws\Jws; use Magento\Framework\Jwt\Jws\JwsHeader; use Magento\Framework\Jwt\Jws\JwsInterface; use Magento\Framework\Jwt\Jws\JwsSignatureJwks; use Magento\Framework\Jwt\Payload\ClaimsPayload; use Magento\Framework\Jwt\Payload\ClaimsPayloadInterface; use Magento\Framework\Jwt\Payload\NestedPayloadInterface; use Magento\Framework\Jwt\Unsecured\NoEncryption; use Magento\Framework\Jwt\Unsecured\UnsecuredJwt; use Magento\Framework\Jwt\Unsecured\UnsecuredJwtInterface; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; class JwtManagerTest extends TestCase { /** * @var JwtManagerInterface */ private $manager; protected function setUp(): void { parent::setUp(); $objectManager = Bootstrap::getObjectManager(); $this->manager = $objectManager->get(JwtManagerInterface::class); } /** * Verify that the manager is able to create and read token data correctly. * * @param JwtInterface $jwt * @param EncryptionSettingsInterface $encryption * @param EncryptionSettingsInterface[] $readEncryption * @return void * * @dataProvider getTokenVariants */ public function testCreateRead( JwtInterface $jwt, EncryptionSettingsInterface $encryption, array $readEncryption ): void { $token = $this->manager->create($jwt, $encryption); $recreated = $this->manager->read($token, $readEncryption); //Verifying header if ((!$jwt instanceof JwsInterface && !$jwt instanceof JweInterface) || ($jwt instanceof JwsInterface && count($jwt->getProtectedHeaders()) == 1) || ($jwt instanceof JweInterface && !$jwt->getPerRecipientUnprotectedHeaders()) ) { $this->verifyAgainstHeaders([$jwt->getHeader()], $recreated->getHeader()); } if ($readEncryption instanceof JwsSignatureJwks) { if ($kid = $readEncryption->getJwkSet()->getKeys()[0]->getKeyId()) { $this->assertNotNull($jwt->getHeader()->getParameter('kid')); $this->assertEquals($kid, $jwt->getHeader()->getParameter('kid')); } } //Verifying payload $this->assertEquals($jwt->getPayload()->getContent(), $recreated->getPayload()->getContent()); if ($jwt->getPayload() instanceof ClaimsPayloadInterface) { $this->assertInstanceOf(ClaimsPayloadInterface::class, $recreated->getPayload()); } if ($jwt->getPayload() instanceof NestedPayloadInterface) { $this->assertInstanceOf(NestedPayloadInterface::class, $recreated->getPayload()); } //JWT type specific validation if ($jwt instanceof JwsInterface) { $this->assertInstanceOf(JwsInterface::class, $recreated); /** @var JwsInterface $recreated */ if (!$jwt->getUnprotectedHeaders()) { $this->assertNull($recreated->getUnprotectedHeaders()); } else { $this->assertTrue(count($recreated->getUnprotectedHeaders()) >= 1); $this->verifyAgainstHeaders($jwt->getUnprotectedHeaders(), $recreated->getUnprotectedHeaders()[0]); } $this->verifyAgainstHeaders($jwt->getProtectedHeaders(), $recreated->getProtectedHeaders()[0]); } elseif ($jwt instanceof JweInterface) { $this->assertInstanceOf(JweInterface::class, $recreated); /** @var JweInterface $recreated */ if (!$jwt->getPerRecipientUnprotectedHeaders()) { $this->assertNull($recreated->getPerRecipientUnprotectedHeaders()); } else { $this->assertTrue(count($recreated->getPerRecipientUnprotectedHeaders()) >= 1); $this->verifyAgainstHeaders( $jwt->getPerRecipientUnprotectedHeaders(), $recreated->getPerRecipientUnprotectedHeaders()[0] ); } if (!$jwt->getSharedUnprotectedHeader()) { $this->assertNull($recreated->getSharedUnprotectedHeader()); } else { $this->verifyAgainstHeaders( [$jwt->getSharedUnprotectedHeader()], $recreated->getSharedUnprotectedHeader() ); } $this->verifyAgainstHeaders([$jwt->getProtectedHeader()], $recreated->getProtectedHeader()); $payload = $jwt->getPayload(); if ($payload instanceof ClaimsPayloadInterface) { foreach ($payload->getClaims() as $claim) { $header = $recreated->getProtectedHeader()->getParameter($claim->getName()); if ($claim->isHeaderDuplicated()) { $this->assertNotNull($header); $this->assertEquals($claim->getValue(), $header->getValue()); } else { $this->assertNull($header); } } } } if ($jwt instanceof UnsecuredJwtInterface) { $this->assertInstanceOf(UnsecuredJwtInterface::class, $recreated); /** @var UnsecuredJwt $recreated */ if (!$jwt->getUnprotectedHeaders()) { $this->assertNull($recreated->getUnprotectedHeaders()); } else { $this->assertTrue(count($recreated->getUnprotectedHeaders()) >= 1); $this->verifyAgainstHeaders($jwt->getUnprotectedHeaders(), $recreated->getUnprotectedHeaders()[0]); } $this->verifyAgainstHeaders($jwt->getProtectedHeaders(), $recreated->getProtectedHeaders()[0]); } } public function getTokenVariants(): array { /** @var JwkFactory $jwkFactory */ $jwkFactory = Bootstrap::getObjectManager()->get(JwkFactory::class); $flatJws = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('custom-header', 'value'), new PrivateHeaderParameter('another-custom-header', 'value2') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2'), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ), null ); $jwsWithUnprotectedHeader = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('custom-header', 'value'), new Critical(['magento']) ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2'), new ExpirationTime(new \DateTimeImmutable()) ] ), [ new JwsHeader( [ new PublicHeaderParameter('public-header', 'magento', 'public-value') ] ) ] ); $compactJws = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), new JwsHeader( [ new PrivateHeaderParameter('test3', true), new PublicHeaderParameter('test4', 'magento', 'value-another') ] ) ], new ClaimsPayload([ new Issuer('magento.com'), new JwtId(), new Subject('stuff') ]), [ new JwsHeader([new PrivateHeaderParameter('public', 'header1')]), new JwsHeader([new PrivateHeaderParameter('public2', 'header')]) ] ); $flatJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), null, null, new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonFlatSharedHeaderJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), new JweHeader( [ new PrivateHeaderParameter('mage', 'test') ] ), null, new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonFlatJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), null, [ new JweHeader( [ new PrivateHeaderParameter('mage', 'test') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), new JweHeader( [ new PrivateHeaderParameter('mage', 'test') ] ), [ new JweHeader([new PrivateHeaderParameter('tst', 2)]), new JweHeader([new PrivateHeaderParameter('test2', 3)]) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonJweKids = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), ] ), null, [ new JweHeader([new PrivateHeaderParameter('tst', 2), new KeyId('2')]), new JweHeader([new PrivateHeaderParameter('test2', 3), new KeyId('1')]) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $flatUnsecured = new UnsecuredJwt( [ new JwsHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ), null ); //Keys [$rsaPrivate, $rsaPublic] = $this->createRsaKeys(); $ecKeys = $this->createEcKeys(); $sharedSecret = random_bytes(2048); return [ 'jws-HS256' => [ $flatJws, $enc = new JwsSignatureJwks($jwkFactory->createHs256($sharedSecret)), [$enc] ], 'jws-HS384' => [ $flatJws, $enc = new JwsSignatureJwks($jwkFactory->createHs384($sharedSecret, '3')), [$enc] ], 'jws-HS512' => [ $jwsWithUnprotectedHeader, $enc = new JwsSignatureJwks($jwkFactory->createHs512($sharedSecret)), [$enc] ], 'jws-RS256' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignRs256($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyRs256($rsaPublic))] ], 'jws-RS384' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignRs384($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyRs384($rsaPublic))] ], 'jws-RS512' => [ $jwsWithUnprotectedHeader, new JwsSignatureJwks($jwkFactory->createSignRs512($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyRs512($rsaPublic))] ], 'jws-json-multiple-signatures' => [ $compactJws, new JwsSignatureJwks( new JwkSet( [ $jwkFactory->createHs384($sharedSecret), $jwkFactory->createSignRs256($rsaPrivate, 'pass') ] ) ), [ new JwsSignatureJwks( new JwkSet( [$jwkFactory->createHs384($sharedSecret), $jwkFactory->createVerifyRs256($rsaPublic)] ) ) ] ], 'jws-json-multiple-signatures-one-read' => [ $compactJws, new JwsSignatureJwks( new JwkSet( [ $jwkFactory->createHs384($sharedSecret), $jwkFactory->createSignRs256($rsaPrivate, 'pass') ] ) ), [new JwsSignatureJwks($jwkFactory->createVerifyRs256($rsaPublic))] ], 'jws-ES256' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignEs256($ecKeys[256][0], 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyEs256($ecKeys[256][1]))] ], 'jws-ES384' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignEs384($ecKeys[384][0], 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyEs384($ecKeys[384][1]))] ], 'jws-ES512' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignEs512($ecKeys[512][0], 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyEs512($ecKeys[512][1]))] ], 'jws-PS256' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignPs256($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyPs256($rsaPublic))] ], 'jws-PS384' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignPs384($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyPs384($rsaPublic))] ], 'jws-PS512' => [ $flatJws, new JwsSignatureJwks($jwkFactory->createSignPs512($rsaPrivate, 'pass')), [new JwsSignatureJwks($jwkFactory->createVerifyPs512($rsaPublic))] ], 'jwe-A128KW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createA128KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createA128KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-A192KW' => [ $jsonFlatSharedHeaderJwe, new JweEncryptionJwks( $jwkFactory->createA192KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createA192KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-A256KW' => [ $jsonFlatJwe, new JweEncryptionJwks( $jwkFactory->createA256KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createA256KW($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-multiple-recipients' => [ $jsonJwe, new JweEncryptionJwks( new JwkSet( [ $jwkFactory->createA256KW($sharedSecret), $jwkFactory->createA128KW($sharedSecret) ] ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( new JwkSet( [ $jwkFactory->createA256KW($sharedSecret), ] ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-rsa-oaep' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptRsaOaep($rsaPublic), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createDecryptRsaOaep($rsaPrivate, 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-rsa-oaep-256' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptRsaOaep256($rsaPublic), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192GCM ), [ new JweEncryptionJwks( $jwkFactory->createDecryptRsaOaep256($rsaPrivate, 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192GCM ) ] ], 'jwe-dir' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createDir( $sharedSecret, JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192_HS384 ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192_HS384 ), [ new JweEncryptionJwks( $jwkFactory->createDir( $sharedSecret, JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192_HS384 ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A192_HS384 ) ] ], 'jwe-multiple-recipients-kids' => [ $jsonJweKids, new JweEncryptionJwks( new JwkSet( [ $jwkFactory->createEncryptRsaOaep256($rsaPublic, '2'), $jwkFactory->createA256KW($sharedSecret, '1') ] ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( new JwkSet( [ $jwkFactory->createDecryptRsaOaep256($rsaPrivate, 'pass', '2') ] ), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-ECDH-ES-with-EC' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptEcdhEsWithEc($ecKeys[256][1]), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createDecryptEcdhEsWithEc($ecKeys[256][0], 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-ECDH-ES-A128-with-EC' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptEcdhEsA128kwWithEc($ecKeys[256][1]), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createDecryptEcdhEsA128kwWithEc($ecKeys[256][0], 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-ECDH-ES-A192-with-EC' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptEcdhEsA192kwWithEc($ecKeys[256][1]), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createDecryptEcdhEsA192kwWithEc($ecKeys[256][0], 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-ECDH-ES-A256-with-EC' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createEncryptEcdhEsA256kwWithEc($ecKeys[256][1]), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ), [ new JweEncryptionJwks( $jwkFactory->createDecryptEcdhEsA256kwWithEc($ecKeys[256][0], 'pass'), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128_HS256 ) ] ], 'jwe-A128GCMKW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createA128Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createA128Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'jwe-A192GCMKW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createA192Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createA192Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'jwe-A256GCMKW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createA256Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createA256Gcmkw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'jwe-PBES2-HS256+A128KW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createPbes2Hs256A128kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createPbes2Hs256A128kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'jwe-PBES2-HS384+A192KW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createPbes2Hs384A192kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createPbes2Hs384A192kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'jwe-PBES2-HS512+A256KW' => [ $flatJwe, new JweEncryptionJwks( $jwkFactory->createPbes2Hs512A256kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ), [ new JweEncryptionJwks( $jwkFactory->createPbes2Hs512A256kw($sharedSecret), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ) ] ], 'unsecured-jwt' => [ $flatUnsecured, new NoEncryption(), [new NoEncryption()] ] ]; } /** * Test reading headers. * * @param JwtInterface $tokenData * @param EncryptionSettingsInterface $settings * @return void * * @dataProvider getJwtsForHeaders */ public function testReadHeaders(JwtInterface $tokenData, EncryptionSettingsInterface $settings): void { $token = $this->manager->create($tokenData, $settings); $headers = $this->manager->readHeaders($token); /** @var HeaderInterface[] $expectedHeaders */ $expectedHeaders = []; if ($tokenData instanceof JwsInterface) { $expectedHeaders = $tokenData->getProtectedHeaders(); if ($tokenData->getUnprotectedHeaders()) { $expectedHeaders = array_merge($expectedHeaders, $tokenData->getUnprotectedHeaders()); } } elseif ($tokenData instanceof JweInterface) { $expectedHeaders[] = $tokenData->getProtectedHeader(); if ($tokenData->getSharedUnprotectedHeader()) { $expectedHeaders[] = $tokenData->getSharedUnprotectedHeader(); } if ($tokenData->getPerRecipientUnprotectedHeaders()) { $expectedHeaders = array_merge($expectedHeaders, $tokenData->getPerRecipientUnprotectedHeaders()); } } elseif ($tokenData instanceof UnsecuredJwtInterface) { $expectedHeaders = $tokenData->getProtectedHeaders(); if ($tokenData->getUnprotectedHeaders()) { $expectedHeaders = array_merge($expectedHeaders, $tokenData->getUnprotectedHeaders()); } } foreach ($headers as $header) { $this->verifyAgainstHeaders($expectedHeaders, $header); } } public function getJwtsForHeaders(): array { /** @var JwkFactory $jwkFactory */ $jwkFactory = Bootstrap::getObjectManager()->get(JwkFactory::class); $flatJws = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('custom-header', 'value'), new PrivateHeaderParameter('another-custom-header', 'value2') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2'), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ), null ); $flatJsonJws = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('custom-header', 'value'), new Critical(['magento']) ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2'), new ExpirationTime(new \DateTimeImmutable()) ] ), [ new JwsHeader( [ new PublicHeaderParameter('public-header', 'magento', 'public-value') ] ) ] ); $jsonJws = new Jws( [ new JwsHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), new JwsHeader( [ new PrivateHeaderParameter('test3', true), new PublicHeaderParameter('test4', 'magento', 'value-another') ] ) ], new ClaimsPayload([ new Issuer('magento.com'), new JwtId(), new Subject('stuff') ]), [ new JwsHeader([new PrivateHeaderParameter('public', 'header1')]), new JwsHeader([new PrivateHeaderParameter('public2', 'header')]) ] ); $flatJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), null, null, new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonFlatJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), null, [ new JweHeader( [ new PrivateHeaderParameter('mage', 'test') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $jsonJwe = new Jwe( new JweHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ), new JweHeader( [ new PrivateHeaderParameter('mage', 'test') ] ), [ new JweHeader([new PrivateHeaderParameter('tst', 2)]), new JweHeader([new PrivateHeaderParameter('test2', 3)]) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ) ); $flatUnsecured = new UnsecuredJwt( [ new JwsHeader( [ new PrivateHeaderParameter('test', true), new PublicHeaderParameter('test2', 'magento', 'value') ] ) ], new ClaimsPayload( [ new PrivateClaim('custom-claim', 'value'), new PrivateClaim('custom-claim2', 'value2', true), new PrivateClaim('custom-claim3', 'value3'), new IssuedAt(new \DateTimeImmutable()), new Issuer('magento.com') ] ), null ); $sharedSecret = random_bytes(2048); $jwsJwk = $jwkFactory->createHs256($sharedSecret); $jweJwk = $jwkFactory->createA128KW($sharedSecret); $jwsSettings = new JwsSignatureJwks($jwsJwk); $jsonJwsSettings = new JwsSignatureJwks(new JwkSet([$jwsJwk, $jwsJwk])); $jweJwkSettings = new JweEncryptionJwks( $jweJwk, JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ); $jsonJweSettings = new JweEncryptionJwks( new JwkSet([$jweJwk, $jweJwk]), JweEncryptionSettingsInterface::CONTENT_ENCRYPTION_ALGO_A128GCM ); return [ 'jws' => [$flatJws, $jwsSettings], 'flat-jws' => [$flatJsonJws, $jwsSettings], 'json-jws' => [$jsonJws, $jsonJwsSettings], 'jwe' => [$flatJwe, $jweJwkSettings], 'flat-jwe' => [$jsonFlatJwe, $jweJwkSettings], 'json-jwe' => [$jsonJwe, $jsonJweSettings], 'none-jws' => [$flatUnsecured, new NoEncryption()] ]; } private function validateHeader(HeaderInterface $expected, HeaderInterface $actual): void { if (count($expected->getParameters()) > count($actual->getParameters())) { throw new \InvalidArgumentException('Missing header parameters'); } foreach ($expected->getParameters() as $parameter) { if ($actual->getParameter($parameter->getName()) === null) { throw new \InvalidArgumentException('Missing header parameters'); } if ($actual->getParameter($parameter->getName())->getValue() !== $parameter->getValue()) { throw new \InvalidArgumentException('Invalid header data'); } } } private function verifyAgainstHeaders(array $expected, HeaderInterface $actual): void { $oneIsValid = false; foreach ($expected as $item) { try { $this->validateHeader($item, $actual); $oneIsValid = true; break; } catch (\InvalidArgumentException $ex) { $oneIsValid = false; } } $this->assertTrue($oneIsValid); } /** * Create RSA key-pair. * * @return string[] With 1st element as private key, second - public. */ private function createRsaKeys(): array { $rsaPrivateResource = openssl_pkey_new(['private_key_bites' => 512, 'private_key_type' => OPENSSL_KEYTYPE_RSA]); if ($rsaPrivateResource === false) { throw new \RuntimeException('Failed to create RSA keypair'); } $rsaPublic = openssl_pkey_get_details($rsaPrivateResource)['key']; if (!openssl_pkey_export($rsaPrivateResource, $rsaPrivate, 'pass')) { throw new \RuntimeException('Failed to read RSA private key'); } $this->freeResource($rsaPrivateResource); return [$rsaPrivate, $rsaPublic]; } /** * Create EC key pairs for with different curves. * * @return array Keys - bits, values contain 2 elements: 0 => private, 1 => public. */ private function createEcKeys(): array { $curveNameMap = [ 256 => 'prime256v1', 384 => 'secp384r1', 512 => 'secp521r1' ]; $ecKeys = []; foreach ($curveNameMap as $bits => $curve) { $privateResource = openssl_pkey_new(['curve_name' => $curve, 'private_key_type' => OPENSSL_KEYTYPE_EC]); if ($privateResource === false) { throw new \RuntimeException('Failed to create EC keypair'); } $esPublic = openssl_pkey_get_details($privateResource)['key']; if (!openssl_pkey_export($privateResource, $esPrivate, 'pass')) { throw new \RuntimeException('Failed to read EC private key'); } $this->freeResource($privateResource); $ecKeys[$bits] = [$esPrivate, $esPublic]; unset($privateResource, $esPublic, $esPrivate); } return $ecKeys; } /** * @param mixed $resource * * @return void */ private function freeResource($resource): void { if (\is_resource($resource) && (version_compare(PHP_VERSION, '8.0') < 0)) { openssl_free_key($resource); } } }