From 9ac7721258cb4b78bd29f1746e6ba3abd63fc1d9 Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 14:39:37 +0100 Subject: [PATCH 1/8] Nested Token Support Fixes #65 --- .../Source/AbstractSource.php | 2 +- .../Source/Checker/ClaimChecker.php | 2 +- .../Source/Checker/HeaderChecker.php | 2 +- .../Encryption/AbstractEncryptionSource.php | 3 +- .../Source/Encryption/JWELoader.php | 16 +- .../Source/Encryption/NestedTokenLoader.php | 174 ++++++++++ .../Source/KeyManagement/JWKSource/Secret.php | 2 +- .../Source/KeyManagement/JWKUriSource.php | 2 +- .../Signature/AbstractSignatureSource.php | 2 +- .../Source/Signature/JWSLoader.php | 10 +- .../Helper/ConfigurationHelper.php | 38 +++ .../JoseFramework/JoseFrameworkBundle.php | 1 + .../Resources/config/nested_token_loaders.yml | 7 + .../NestedTokenLoaderConfigurationTest.php | 176 ++++++++++ .../Encryption/NestedTokenLoaderTest.php | 132 ++++++++ .../DependencyInjection/TestExtension.php | 1 + .../Tests/config/config_test.yml | 6 + .../Encryption/NestedTokenLoader.php | 92 ++++++ .../Encryption/NestedTokenLoaderFactory.php | 49 +++ ...NestingTokenUsingNestedTokenLoaderTest.php | 303 ++++++++++++++++++ 20 files changed, 999 insertions(+), 21 deletions(-) create mode 100644 src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php create mode 100644 src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml create mode 100644 src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php create mode 100644 src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php create mode 100644 src/Component/Encryption/NestedTokenLoader.php create mode 100644 src/Component/Encryption/NestedTokenLoaderFactory.php create mode 100644 src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/AbstractSource.php b/src/Bundle/JoseFramework/DependencyInjection/Source/AbstractSource.php index 6f8c6086..e2b8f680 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/AbstractSource.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/AbstractSource.php @@ -60,7 +60,7 @@ public function addConfiguration(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end(); } diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/ClaimChecker.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/ClaimChecker.php index 97b73b75..3622f7a4 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/ClaimChecker.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/ClaimChecker.php @@ -81,7 +81,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable') + ->variablePrototype() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/HeaderChecker.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/HeaderChecker.php index 1ddfa6ba..f60579d7 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/HeaderChecker.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Checker/HeaderChecker.php @@ -81,7 +81,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable') + ->variablePrototype() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/AbstractEncryptionSource.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/AbstractEncryptionSource.php index 718dab12..92972785 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/AbstractEncryptionSource.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/AbstractEncryptionSource.php @@ -52,7 +52,6 @@ public function getNodeDefinition(NodeDefinition $node) ->info('A list of supported compression methods.') ->useAttributeAsKey('name') ->defaultValue(['DEF']) - ->requiresAtLeastOneElement() ->scalarPrototype()->end() ->end() ->arrayNode('tags') @@ -60,7 +59,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/JWELoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/JWELoader.php index 9ed2c6a7..8570f871 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/JWELoader.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/JWELoader.php @@ -65,7 +65,7 @@ public function getNodeDefinition(NodeDefinition $node) ->arrayNode($this->name()) ->requiresAtLeastOneElement() ->useAttributeAsKey('name') - ->prototype('array') + ->arrayPrototype() ->children() ->booleanNode('is_public') ->info('If true, the service will be public, else private.') @@ -75,39 +75,39 @@ public function getNodeDefinition(NodeDefinition $node) ->info('A list of key encryption algorithm aliases.') ->useAttributeAsKey('name') ->isRequired() - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('content_encryption_algorithms') ->info('A list of key encryption algorithm aliases.') ->useAttributeAsKey('name') ->isRequired() - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('compression_methods') ->info('A list of compression method aliases.') ->useAttributeAsKey('name') - ->isRequired() - ->prototype('scalar')->end() + ->defaultValue(['DEF']) + ->scalarPrototype()->end() ->end() ->arrayNode('serializers') ->info('A list of signature serializer aliases.') ->useAttributeAsKey('name') ->requiresAtLeastOneElement() - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('header_checkers') ->info('A list of header checker aliases.') ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('tags') ->info('A list of tags to be associated to the service.') ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php new file mode 100644 index 00000000..1058cd29 --- /dev/null +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php @@ -0,0 +1,174 @@ +isEnabled()) { + return; + } + $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config')); + $loader->load('nested_token_loaders.yml'); + + foreach ($configs[$this->name()] as $name => $itemConfig) { + $service_id = sprintf('jose.nested_token_loader.%s', $name); + $definition = new Definition(NestedTokenLoader::class); + $definition + ->setFactory([new Reference(NestedTokenLoaderFactory::class), 'create']) + ->setArguments([ + $itemConfig['jwe_serializers'], + $itemConfig['key_encryption_algorithms'], + $itemConfig['content_encryption_algorithms'], + $itemConfig['compression_methods'], + $itemConfig['jwe_header_checkers'], + $itemConfig['jws_serializers'], + $itemConfig['signature_algorithms'], + $itemConfig['jws_header_checkers'], + ]) + ->addTag('jose.nested_token_loader') + ->setPublic($itemConfig['is_public']); + foreach ($itemConfig['tags'] as $id => $attributes) { + $definition->addTag($id, $attributes); + } + $container->setDefinition($service_id, $definition); + } + } + + public function getNodeDefinition(NodeDefinition $node) + { + if (!$this->isEnabled()) { + return; + } + $node + ->children() + ->arrayNode($this->name()) + ->treatNullLike([]) + ->treatFalseLike([]) + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->booleanNode('is_public') + ->info('If true, the service will be public, else private.') + ->defaultTrue() + ->end() + ->arrayNode('signature_algorithms') + ->info('A list of signature algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('key_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('content_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('compression_methods') + ->info('A list of compression method aliases.') + ->useAttributeAsKey('name') + ->defaultValue(['DEF']) + ->scalarPrototype()->end() + ->end() + ->arrayNode('jws_serializers') + ->info('A list of JWS serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('jwe_serializers') + ->info('A list of JWE serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('jws_header_checkers') + ->info('A list of header checker aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->scalarPrototype()->end() + ->end() + ->arrayNode('jwe_header_checkers') + ->info('A list of header checker aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->scalarPrototype()->end() + ->end() + ->arrayNode('tags') + ->info('A list of tags to be associated to the service.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->variablePrototype()->end() + ->end() + ->end() + ->end() + ->end() + ->end(); + } + + /** + * {@inheritdoc} + */ + public function prepend(ContainerBuilder $container, array $config): array + { + return []; + } + + /** + * @return bool + */ + private function isEnabled(): bool + { + return class_exists(JWEDecrypterFactory::class) + && class_exists(JWSVerifierFactory::class) + && class_exists(HeaderCheckerManagerFactory::class); + } +} diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSource/Secret.php b/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSource/Secret.php index 0b6be909..a6425ddd 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSource/Secret.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSource/Secret.php @@ -65,7 +65,7 @@ public function addConfiguration(NodeDefinition $node) ->info('Additional values to be added to the key.') ->defaultValue([]) ->useAttributeAsKey('key') - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end(); } diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKUriSource.php b/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKUriSource.php index b6ec3a11..b94f8ad8 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKUriSource.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKUriSource.php @@ -81,7 +81,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->booleanNode('is_public') ->info('If true, the service will be public, else private.') diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/AbstractSignatureSource.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/AbstractSignatureSource.php index 89054d97..6e0ca9c4 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/AbstractSignatureSource.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/AbstractSignatureSource.php @@ -46,7 +46,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/JWSLoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/JWSLoader.php index 24a31bc4..ee8e43b1 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/JWSLoader.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Signature/JWSLoader.php @@ -63,7 +63,7 @@ public function getNodeDefinition(NodeDefinition $node) ->arrayNode($this->name()) ->requiresAtLeastOneElement() ->useAttributeAsKey('name') - ->prototype('array') + ->arrayPrototype() ->children() ->booleanNode('is_public') ->info('If true, the service will be public, else private.') @@ -73,27 +73,27 @@ public function getNodeDefinition(NodeDefinition $node) ->info('A list of signature algorithm aliases.') ->useAttributeAsKey('name') ->isRequired() - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('serializers') ->info('A list of signature serializer aliases.') ->useAttributeAsKey('name') ->requiresAtLeastOneElement() - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('header_checkers') ->info('A list of header checker aliases.') ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('scalar')->end() + ->scalarPrototype()->end() ->end() ->arrayNode('tags') ->info('A list of tags to be associated to the service.') ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) - ->prototype('variable')->end() + ->variablePrototype()->end() ->end() ->end() ->end() diff --git a/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php b/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php index a7342301..fa9e76c6 100644 --- a/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php +++ b/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php @@ -126,6 +126,44 @@ public static function addJWSLoader(ContainerBuilder $container, string $name, a self::updateJoseConfiguration($container, $config, 'jws'); } + /** + * @param ContainerBuilder $container + * @param string $name + * @param string[] $jwe_serializers + * @param string[] $key_encryption_algorithms + * @param string[] $content_encryption_algorithms + * @param string[] $compression_methods + * @param string[] $jwe_header_checkers + * @param string[] $jws_serializers + * @param string[] $signature_algorithms + * @param string[] $jws_header_checkers + * @param bool $is_public + * @param array $tags + */ + public static function addNestedTokenLoader(ContainerBuilder $container, string $name, array $jwe_serializers, array $key_encryption_algorithms, array $content_encryption_algorithms, array $compression_methods, array $jwe_header_checkers, array $jws_serializers, array $signature_algorithms, array $jws_header_checkers, bool $is_public = true, array $tags = []) + { + $config = [ + self::BUNDLE_ALIAS => [ + 'nested_token_loaders' => [ + $name => [ + 'is_public' => $is_public, + 'jwe_serializers' => $jwe_serializers, + 'key_encryption_algorithms' => $key_encryption_algorithms, + 'content_encryption_algorithms' => $content_encryption_algorithms, + 'compression_methods' => $compression_methods, + 'jwe_header_checkers' => $jwe_header_checkers, + 'jws_serializers' => $jws_serializers, + 'signature_algorithms' => $signature_algorithms, + 'jws_header_checkers' => $jws_header_checkers, + 'tags' => $tags, + ], + ], + ], + ]; + + self::updateJoseConfiguration($container, $config, 'nested_token_loaders'); + } + /** * @param ContainerBuilder $container * @param string $name diff --git a/src/Bundle/JoseFramework/JoseFrameworkBundle.php b/src/Bundle/JoseFramework/JoseFrameworkBundle.php index 88a97743..490f7856 100644 --- a/src/Bundle/JoseFramework/JoseFrameworkBundle.php +++ b/src/Bundle/JoseFramework/JoseFrameworkBundle.php @@ -73,6 +73,7 @@ private function getSources(): array new Source\Console\ConsoleSource(), new Source\Signature\SignatureSource(), new Source\Encryption\EncryptionSource(), + new Source\Encryption\NestedTokenLoader(), new Source\KeyManagement\KeyManagementSource(), ]; } diff --git a/src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml b/src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml new file mode 100644 index 00000000..0f2f411e --- /dev/null +++ b/src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml @@ -0,0 +1,7 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: true + + Jose\Component\Encryption\NestedTokenLoaderFactory: ~ diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php new file mode 100644 index 00000000..395d5ecf --- /dev/null +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php @@ -0,0 +1,176 @@ +markTestSkipped('The component "web-token/jwt-encryption" is not installed.'); + } + if (!class_exists(JWSLoaderFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + if (!class_exists(HeaderCheckerManagerFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + } + + /** + * {@inheritdoc} + */ + protected function getConfiguration() + { + return new Configuration('jose', [ + new Source\Core\CoreSource(), + new Source\Checker\CheckerSource(), + new Source\Signature\SignatureSource(), + new Source\Encryption\EncryptionSource(), + new Source\Encryption\NestedTokenLoader(), + ]); + } + + /** + * @test + */ + public function theConfigurationIsValidIfNoConfigurationIsSet() + { + $this->assertConfigurationIsValid( + [] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfConfigurationIsFalse() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token_loaders' => false, + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfConfigurationIsEmpty() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token_loaders' => [], + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoSignatureAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token_loaders' => [ + 'foo' => [], + ], + ], + ], + 'The child node "signature_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoKeyEncryptionAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token_loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + ], + ], + ], + ], + 'The child node "key_encryption_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token_loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + ], + ], + ], + ], + 'The child node "content_encryption_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsValid() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token_loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + ], + ], + ], + ] + ); + } +} diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php new file mode 100644 index 00000000..2e826eec --- /dev/null +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php @@ -0,0 +1,132 @@ +markTestSkipped('The component "web-token/jwt-encryption" is not installed.'); + } + if (!class_exists(JWSLoaderFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + if (!class_exists(HeaderCheckerManagerFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + } + + /** + * @test + */ + public function theNestedTokenLoaderFactoryIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has(NestedTokenLoaderFactory::class)); + } + + /** + * @test + */ + public function theNestedTokenLoaderFromTheConfigurationIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has('jose.nested_token_loader.nested_token_loader_1')); + } + + /** + * @test + */ + public function theNestedTokenLoaderFromTheConfigurationHelperIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has('jose.nested_token_loader.nested_token_loader_2')); + } + + /** + * @test + */ + public function aNestedTokenCanBeDecryptedAndVerified() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + + /** @var NestedTokenLoader $loader */ + $loader = $container->get('jose.nested_token_loader.nested_token_loader_2'); + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + $encryption_key_set = JWKSet::createFromKeys([$encryption_key]); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + $signature_key_set = JWKSet::createFromKeys([ + $signature_key + ]); + + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + $token = 'eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ.a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0.GbX1i9kXz0sxXPmA.SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM.KnIKEhN8U-3C9s4gtSpjSw'; + + $jws = $loader->load($token, $encryption_key_set, $signature_key_set, $signature); + self::assertEquals($payload, $jws->getPayload()); + self::assertEquals(0, $signature); + } +} diff --git a/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php b/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php index 316c1e09..2320a1c4 100644 --- a/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php +++ b/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php @@ -62,5 +62,6 @@ public function prepend(ContainerBuilder $container) ConfigurationHelper::addJWEDecrypter($container, 'loader2', ['RSA-OAEP-256'], ['A128GCM'], ['DEF'], true); ConfigurationHelper::addJWESerializer($container, 'jwe_serializer2', ['jwe_compact', 'jwe_json_flattened', 'jwe_json_general'], true); ConfigurationHelper::addJWELoader($container, 'jwe_loader2', ['jwe_compact'], ['RSA-OAEP-256'], ['A128GCM'], ['DEF'], [], true); + ConfigurationHelper::addNestedTokenLoader($container, 'nested_token_loader_2', ['jwe_compact'], ['RSA-OAEP'], ['A128GCM'], ['DEF'], [], ['jws_compact'], ['PS256'], [], true, []); } } diff --git a/src/Bundle/JoseFramework/Tests/config/config_test.yml b/src/Bundle/JoseFramework/Tests/config/config_test.yml index c36c8fb9..c1b0f556 100644 --- a/src/Bundle/JoseFramework/Tests/config/config_test.yml +++ b/src/Bundle/JoseFramework/Tests/config/config_test.yml @@ -74,6 +74,12 @@ jose: content_encryption_algorithms: ['A256CBC-HS512'] compression_methods: [] is_public: true + nested_token_loaders: + nested_token_loader_1: + signature_algorithms: ['PS256'] + key_encryption_algorithms: ['RSA-OAEP'] + content_encryption_algorithms: ['A128GCM'] + is_public: true keys: jwk1: jwk: diff --git a/src/Component/Encryption/NestedTokenLoader.php b/src/Component/Encryption/NestedTokenLoader.php new file mode 100644 index 00000000..8dfec81d --- /dev/null +++ b/src/Component/Encryption/NestedTokenLoader.php @@ -0,0 +1,92 @@ +jweLoader = $jweLoader; + $this->jwsLoader = $jwsLoader; + } + + /** + * @param string $token + * @param JWKSet $encryptionKeySet + * @param JWKSet $signatureKeySet + * @param int|null $signature + * + * @return JWS + * + * @throws \Exception + */ + public function load(string $token, JWKSet $encryptionKeySet, JWKSet $signatureKeySet, ?int &$signature = null): JWS + { + $recipient = null; + $jwe = $this->jweLoader->loadAndDecryptWithKeySet($token, $encryptionKeySet, $recipient); + $this->checkContentTypeHeader($jwe, $recipient); + if (null === $jwe->getPayload()) { + throw new \InvalidArgumentException('The token has no payload.'); + } + + return $this->jwsLoader->loadAndVerifyWithKeySet($jwe->getPayload(), $signatureKeySet, $signature); + } + + /** + * @param JWE $jwe + * @param int $recipient + * + * @throws \InvalidArgumentException + */ + private function checkContentTypeHeader(JWE $jwe, int $recipient) + { + switch (true) { + case $jwe->hasSharedProtectedHeaderParameter('cty'): + $cty = $jwe->getSharedProtectedHeaderParameter('cty'); + break; + case $jwe->hasSharedHeaderParameter('cty'): + $cty = $jwe->getSharedHeaderParameter('cty'); + break; + case $jwe->getRecipient($recipient)->hasHeaderParameter('cty'): + $cty = $jwe->getRecipient($recipient)->getHeaderParameter('cty'); + break; + default: + throw new \InvalidArgumentException('The token is not a nested token.'); + } + + if (0 !== strcasecmp($cty, 'jwt')) { + throw new \InvalidArgumentException('The token is not a nested token.'); + } + } +} diff --git a/src/Component/Encryption/NestedTokenLoaderFactory.php b/src/Component/Encryption/NestedTokenLoaderFactory.php new file mode 100644 index 00000000..84f443da --- /dev/null +++ b/src/Component/Encryption/NestedTokenLoaderFactory.php @@ -0,0 +1,49 @@ +jweLoaderFactory = $jweLoaderFactory; + $this->jwsLoaderFactory = $jwsLoaderFactory; + } + + public function create(array $jweSerializers, array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithms, array $compressionMethods, array $jweHeaderCheckers, array $jwsSerializers, array $signatureAlgorithms, array $jwsHeaderCheckers): NestedTokenLoader + { + $jweLoader = $this->jweLoaderFactory->create($jweSerializers, $keyEncryptionAlgorithms, $contentEncryptionAlgorithms, $compressionMethods, $jweHeaderCheckers); + $jwsLoader = $this->jwsLoaderFactory->create($jwsSerializers, $signatureAlgorithms, $jwsHeaderCheckers); + + return new NestedTokenLoader($jweLoader, $jwsLoader); + } +} diff --git a/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php b/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php new file mode 100644 index 00000000..24cbfe57 --- /dev/null +++ b/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php @@ -0,0 +1,303 @@ +markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + if (!class_exists(JWSLoader::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + } + + public function testDecryption() + { + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + $encryption_key_set = JWKSet::createFromKeys([$encryption_key]); + + $nestedTokenLoader = $this->getNestedTokenLoaderFactory()->create( + ['jwe_compact', 'jwe_json_flattened', 'jwe_json_general'], + ['RSA-OAEP'], + ['A128GCM'], + ['DEF'], + [], + ['jws_compact', 'jws_json_flattened', 'jws_json_general'], + ['PS256'], + [] + ); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + $signature_key_set = JWKSet::createFromKeys([ + $signature_key + ]); + + $json_compact = 'eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ.a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0.GbX1i9kXz0sxXPmA.SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM.KnIKEhN8U-3C9s4gtSpjSw'; + $json_flattened = '{"encrypted_key": "a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0","protected": "eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ","iv": "GbX1i9kXz0sxXPmA","ciphertext": "SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM","tag": "KnIKEhN8U-3C9s4gtSpjSw"}'; + $json_general = '{"recipients": [{"encrypted_key": "a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0"}],"protected": "eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ","iv": "GbX1i9kXz0sxXPmA","ciphertext": "SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM","tag": "KnIKEhN8U-3C9s4gtSpjSw"}'; + + $loaded_compact_json = $nestedTokenLoader->load($json_compact, $encryption_key_set, $signature_key_set, $json_compact_signature); + self::assertEquals($payload, $loaded_compact_json->getPayload()); + self::assertEquals(0, $json_compact_signature); + + $loaded_flattened_json = $nestedTokenLoader->load($json_flattened, $encryption_key_set, $signature_key_set, $json_flattened_signature); + self::assertEquals($payload, $loaded_flattened_json->getPayload()); + self::assertEquals(0, $json_flattened_signature); + + $loaded_json = $nestedTokenLoader->load($json_general, $encryption_key_set, $signature_key_set, $json_general_signature); + self::assertEquals($payload, $loaded_json->getPayload()); + self::assertEquals(0, $json_general_signature); + } + + /** + * @var JWSLoaderFactory + */ + private $jwsLoaderFactory; + + /** + * @return JWSLoaderFactory + */ + protected function getJWSLoaderFactory(): JWSLoaderFactory + { + if (null === $this->jwsLoaderFactory) { + $this->jwsLoaderFactory = new JWSLoaderFactory( + $this->getJWSSerializerManagerFactory(), + $this->getJWSVerifierFactory(), + $this->getHeaderCheckerManagerFactory() + ); + } + + return $this->jwsLoaderFactory; + } + + /** + * @var JWELoaderFactory + */ + private $jweLoaderFactory; + + /** + * @return JWELoaderFactory + */ + protected function getJWELoaderFactory(): JWELoaderFactory + { + if (null === $this->jweLoaderFactory) { + $this->jweLoaderFactory = new JWELoaderFactory( + $this->getJWESerializerManagerFactory(), + $this->getJWEDecrypterFactory(), + $this->getHeaderCheckerManagerFactory() + ); + } + + return $this->jweLoaderFactory; + } + + /** + * @var NestedTokenLoaderFactory + */ + private $nestedTokenLoaderFactory; + + /** + * @return NestedTokenLoaderFactory + */ + private function getNestedTokenLoaderFactory(): NestedTokenLoaderFactory + { + if (null === $this->nestedTokenLoaderFactory) { + $this->nestedTokenLoaderFactory = new NestedTokenLoaderFactory( + $this->getJWELoaderFactory(), + $this->getJWSLoaderFactory() + ); + } + + return $this->nestedTokenLoaderFactory; + } + + /** + * @return HeaderCheckerManagerFactory + */ + private function getHeaderCheckerManagerFactory(): HeaderCheckerManagerFactory + { + $headerCheckerManagerFactory = new HeaderCheckerManagerFactory(); + $headerCheckerManagerFactory->addTokenTypeSupport(new JWETokenSupport()); + $headerCheckerManagerFactory->addTokenTypeSupport(new JWSTokenSupport()); + + return $headerCheckerManagerFactory; + } + + /** + * @return JwsSerializer\JWSSerializerManagerFactory + */ + private function getJWSSerializerManagerFactory(): JwsSerializer\JWSSerializerManagerFactory + { + $jwsSerializerManagerFactory = new JwsSerializer\JWSSerializerManagerFactory(); + $jwsSerializerManagerFactory->add(new JwsSerializer\CompactSerializer(new StandardConverter())); + $jwsSerializerManagerFactory->add(new JwsSerializer\JSONFlattenedSerializer(new StandardConverter())); + $jwsSerializerManagerFactory->add(new JwsSerializer\JSONGeneralSerializer(new StandardConverter())); + + return $jwsSerializerManagerFactory; + } + + /** + * @return JWSVerifierFactory + */ + private function getJWSVerifierFactory(): JWSVerifierFactory + { + $jwsVerifierFactory = new JWSVerifierFactory( + $this->getAlgorithmManagerFactory() + ); + + return $jwsVerifierFactory; + } + /** + * @var AlgorithmManagerFactory + */ + private $algorithmManagerFactory; + + /** + * @return AlgorithmManagerFactory + */ + private function getAlgorithmManagerFactory(): AlgorithmManagerFactory + { + if (null === $this->algorithmManagerFactory) { + $this->algorithmManagerFactory = new AlgorithmManagerFactory(); + $this->algorithmManagerFactory + ->add('A128GCM', new A128GCM()) + ->add('RSA-OAEP', new RSAOAEP()) + ->add('PS256', new PS256()); + } + + return $this->algorithmManagerFactory; + } + + /** + * @var CompressionMethodManagerFactory + */ + private $compressionMethodManagerFactory; + + /** + * @return CompressionMethodManagerFactory + */ + private function getCompressionMethodManagerFactory(): CompressionMethodManagerFactory + { + if (null === $this->compressionMethodManagerFactory) { + $this->compressionMethodManagerFactory = new CompressionMethodManagerFactory(); + $this->compressionMethodManagerFactory + ->add('DEF', new Compression\Deflate()) + ->add('ZLIB', new Compression\ZLib()) + ->add('GZ', new Compression\GZip()); + } + + return $this->compressionMethodManagerFactory; + } + + /** + * @var JWEDecrypterFactory + */ + private $jweDecrypterFactory; + + /** + * @return JWEDecrypterFactory + */ + private function getJWEDecrypterFactory(): JWEDecrypterFactory + { + if (null === $this->jweDecrypterFactory) { + $this->jweDecrypterFactory = new JWEDecrypterFactory( + $this->getAlgorithmManagerFactory(), + $this->getCompressionMethodManagerFactory() + ); + } + + return $this->jweDecrypterFactory; + } + + /** + * @var null|JweSerializer\JWESerializerManagerFactory + */ + private $jwsSerializerManagerFactory = null; + + /** + * @return JweSerializer\JWESerializerManagerFactory + */ + private function getJWESerializerManagerFactory(): JweSerializer\JWESerializerManagerFactory + { + if (null === $this->jwsSerializerManagerFactory) { + $this->jwsSerializerManagerFactory = new JweSerializer\JWESerializerManagerFactory(); + $this->jwsSerializerManagerFactory->add(new JweSerializer\CompactSerializer(new StandardConverter())); + $this->jwsSerializerManagerFactory->add(new JweSerializer\JSONFlattenedSerializer(new StandardConverter())); + $this->jwsSerializerManagerFactory->add(new JweSerializer\JSONGeneralSerializer(new StandardConverter())); + } + + return $this->jwsSerializerManagerFactory; + } +} From e122ef266b34110a09eaec82c35d6af46f729419 Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 14:40:16 +0100 Subject: [PATCH 2/8] Apply fixes from StyleCI (#84) [ci skip] [skip ci] --- .../Source/Encryption/NestedTokenLoader.php | 6 ++--- .../NestedTokenLoaderConfigurationTest.php | 6 ++--- .../Encryption/NestedTokenLoaderTest.php | 18 ++++++------- .../Encryption/NestedTokenLoader.php | 4 +-- ...NestingTokenUsingNestedTokenLoaderTest.php | 27 ++++++++++--------- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php index 1058cd29..66d8f4e0 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php @@ -19,10 +19,10 @@ use Jose\Component\Encryption\NestedTokenLoaderFactory; use Jose\Component\Signature\JWSVerifierFactory; use Symfony\Component\Config\Definition\Builder\NodeDefinition; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; class NestedTokenLoader implements Source @@ -48,7 +48,7 @@ public function load(array $configs, ContainerBuilder $container) foreach ($configs[$this->name()] as $name => $itemConfig) { $service_id = sprintf('jose.nested_token_loader.%s', $name); - $definition = new Definition(NestedTokenLoader::class); + $definition = new Definition(self::class); $definition ->setFactory([new Reference(NestedTokenLoaderFactory::class), 'create']) ->setArguments([ diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php index 395d5ecf..e0063c6c 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php @@ -144,7 +144,7 @@ public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() [ 'nested_token_loaders' => [ 'foo' => [ - 'signature_algorithms' => ['RS256'], + 'signature_algorithms' => ['RS256'], 'key_encryption_algorithms' => ['RSA-OAEP'], ], ], @@ -164,8 +164,8 @@ public function theConfigurationIsValid() [ 'nested_token_loaders' => [ 'foo' => [ - 'signature_algorithms' => ['RS256'], - 'key_encryption_algorithms' => ['RSA-OAEP'], + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], 'content_encryption_algorithms' => ['A128GCM'], ], ], diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php index 2e826eec..022998d3 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php @@ -109,17 +109,17 @@ public function aNestedTokenCanBeDecryptedAndVerified() 'kty' => 'RSA', 'kid' => 'hobbiton.example', 'use' => 'sig', - 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', - 'e' => 'AQAB', - 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', - 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', - 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', - 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', - 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', - 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', ]); $signature_key_set = JWKSet::createFromKeys([ - $signature_key + $signature_key, ]); $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; diff --git a/src/Component/Encryption/NestedTokenLoader.php b/src/Component/Encryption/NestedTokenLoader.php index 8dfec81d..d95102d0 100644 --- a/src/Component/Encryption/NestedTokenLoader.php +++ b/src/Component/Encryption/NestedTokenLoader.php @@ -47,9 +47,9 @@ public function __construct(JWELoader $jweLoader, JWSLoader $jwsLoader) * @param JWKSet $signatureKeySet * @param int|null $signature * - * @return JWS - * * @throws \Exception + * + * @return JWS */ public function load(string $token, JWKSet $encryptionKeySet, JWKSet $signatureKeySet, ?int &$signature = null): JWS { diff --git a/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php b/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php index 24cbfe57..ec4a77c1 100644 --- a/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php +++ b/src/Component/Encryption/Tests/RFC7520/NestingTokenUsingNestedTokenLoaderTest.php @@ -13,7 +13,10 @@ namespace Jose\Component\Encryption\Tests\RFC7520; +use Jose\Component\Checker\HeaderCheckerManagerFactory; use Jose\Component\Core\AlgorithmManagerFactory; +use Jose\Component\Core\Converter\StandardConverter; +use Jose\Component\Core\JWK; use Jose\Component\Core\JWKSet; use Jose\Component\Encryption\Algorithm\ContentEncryption\A128GCM; use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP; @@ -21,12 +24,9 @@ use Jose\Component\Encryption\Compression\CompressionMethodManagerFactory; use Jose\Component\Encryption\JWEDecrypterFactory; use Jose\Component\Encryption\JWELoaderFactory; -use Jose\Component\Encryption\Serializer as JweSerializer; -use Jose\Component\Checker\HeaderCheckerManagerFactory; -use Jose\Component\Core\Converter\StandardConverter; -use Jose\Component\Core\JWK; use Jose\Component\Encryption\JWETokenSupport; use Jose\Component\Encryption\NestedTokenLoaderFactory; +use Jose\Component\Encryption\Serializer as JweSerializer; use Jose\Component\Signature\Algorithm\PS256; use Jose\Component\Signature\JWSLoader; use Jose\Component\Signature\JWSLoaderFactory; @@ -91,17 +91,17 @@ public function testDecryption() 'kty' => 'RSA', 'kid' => 'hobbiton.example', 'use' => 'sig', - 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', - 'e' => 'AQAB', - 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', - 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', - 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', - 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', - 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', - 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', ]); $signature_key_set = JWKSet::createFromKeys([ - $signature_key + $signature_key, ]); $json_compact = 'eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ.a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0.GbX1i9kXz0sxXPmA.SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM.KnIKEhN8U-3C9s4gtSpjSw'; @@ -219,6 +219,7 @@ private function getJWSVerifierFactory(): JWSVerifierFactory return $jwsVerifierFactory; } + /** * @var AlgorithmManagerFactory */ From a38e68280c60d370fd2ed48013daef0377d21ea8 Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 21:41:02 +0100 Subject: [PATCH 3/8] Nested Token Builder Support --- .../Source/Encryption/NestedToken.php | 111 ++++++++ .../Source/Encryption/NestedTokenBuilder.php | 132 +++++++++ .../Source/Encryption/NestedTokenLoader.php | 170 +++++------- .../Helper/ConfigurationHelper.php | 64 ++++- .../JoseFramework/JoseFrameworkBundle.php | 2 +- ...ted_token_loaders.yml => nested_token.yml} | 1 + .../NestedTokenBuilderConfigurationTest.php | 200 ++++++++++++++ .../Encryption/NestedTokenBuilderTest.php | 142 ++++++++++ .../NestedTokenLoaderConfigurationTest.php | 64 +++-- .../DependencyInjection/TestExtension.php | 1 + .../Tests/config/config_test.yml | 19 +- .../Encryption/NestedTokenBuilder.php | 102 +++++++ .../Encryption/NestedTokenBuilderFactory.php | 77 ++++++ .../Encryption/NestedTokenLoaderFactory.php | 12 + .../Tests/RFC7520/NestingTokenBuilderTest.php | 250 ++++++++++++++++++ 15 files changed, 1209 insertions(+), 138 deletions(-) create mode 100644 src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php create mode 100644 src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php rename src/Bundle/JoseFramework/Resources/config/{nested_token_loaders.yml => nested_token.yml} (72%) create mode 100644 src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php create mode 100644 src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php create mode 100644 src/Component/Encryption/NestedTokenBuilder.php create mode 100644 src/Component/Encryption/NestedTokenBuilderFactory.php create mode 100644 src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php new file mode 100644 index 00000000..d33b0b61 --- /dev/null +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php @@ -0,0 +1,111 @@ +sources = [ + new NestedTokenLoader(), + new NestedTokenBuilder(), + ]; + } + /** + * {@inheritdoc} + */ + public function name(): string + { + return 'nested_token'; + } + + /** + * {@inheritdoc} + */ + public function load(array $configs, ContainerBuilder $container) + { + if (!$this->isEnabled()) { + return; + } + $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config')); + $loader->load('nested_token.yml'); + + if (array_key_exists('nested_token', $configs)) { + foreach ($this->sources as $source) { + $source->load($configs['nested_token'], $container); + } + } + } + + public function getNodeDefinition(NodeDefinition $node) + { + if (!$this->isEnabled()) { + return; + } + $childNode = $node->children() + ->arrayNode($this->name()) + ->treatNullLike([]) + ->treatFalseLike([]); + + foreach ($this->sources as $source) { + $source->getNodeDefinition($childNode); + } + } + + /** + * {@inheritdoc} + */ + public function prepend(ContainerBuilder $container, array $config): array + { + if (!$this->isEnabled()) { + return []; + } + $result = []; + foreach ($this->sources as $source) { + $prepend = $source->prepend($container, $config); + if (!empty($prepend)) { + $result[$source->name()] = $prepend; + } + } + + return $result; + } + + /** + * @return bool + */ + private function isEnabled(): bool + { + return class_exists(JWEDecrypterFactory::class) + && class_exists(JWSVerifierFactory::class) + && class_exists(HeaderCheckerManagerFactory::class); + } +} diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php new file mode 100644 index 00000000..649e6651 --- /dev/null +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php @@ -0,0 +1,132 @@ +name()] as $name => $itemConfig) { + $service_id = sprintf('jose.nested_token_builder.%s', $name); + $definition = new Definition(self::class); + $definition + ->setFactory([new Reference(NestedTokenBuilderFactory::class), 'create']) + ->setArguments([ + $itemConfig['jwe_serializers'], + $itemConfig['key_encryption_algorithms'], + $itemConfig['content_encryption_algorithms'], + $itemConfig['compression_methods'], + $itemConfig['jws_serializers'], + $itemConfig['signature_algorithms'], + ]) + ->addTag('jose.nested_token_builder') + ->setPublic($itemConfig['is_public']); + foreach ($itemConfig['tags'] as $id => $attributes) { + $definition->addTag($id, $attributes); + } + $container->setDefinition($service_id, $definition); + } + } + + public function getNodeDefinition(NodeDefinition $node) + { + $node->children() + ->arrayNode($this->name()) + ->treatNullLike([]) + ->treatFalseLike([]) + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->booleanNode('is_public') + ->info('If true, the service will be public, else private.') + ->defaultTrue() + ->end() + ->arrayNode('signature_algorithms') + ->info('A list of signature algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('key_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('content_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('compression_methods') + ->info('A list of compression method aliases.') + ->useAttributeAsKey('name') + ->defaultValue(['DEF']) + ->scalarPrototype()->end() + ->end() + ->arrayNode('jws_serializers') + ->info('A list of JWS serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('jwe_serializers') + ->info('A list of JWE serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('tags') + ->info('A list of tags to be associated to the service.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->variablePrototype()->end() + ->end() + ->end() + ->end() + ->end(); + } + + /** + * {@inheritdoc} + */ + public function prepend(ContainerBuilder $container, array $config): array + { + return []; + } +} diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php index 66d8f4e0..0521cc89 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php @@ -14,15 +14,10 @@ namespace Jose\Bundle\JoseFramework\DependencyInjection\Source\Encryption; use Jose\Bundle\JoseFramework\DependencyInjection\Source\Source; -use Jose\Component\Checker\HeaderCheckerManagerFactory; -use Jose\Component\Encryption\JWEDecrypterFactory; use Jose\Component\Encryption\NestedTokenLoaderFactory; -use Jose\Component\Signature\JWSVerifierFactory; use Symfony\Component\Config\Definition\Builder\NodeDefinition; -use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; class NestedTokenLoader implements Source @@ -32,7 +27,7 @@ class NestedTokenLoader implements Source */ public function name(): string { - return 'nested_token_loaders'; + return 'loaders'; } /** @@ -40,12 +35,6 @@ public function name(): string */ public function load(array $configs, ContainerBuilder $container) { - if (!$this->isEnabled()) { - return; - } - $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../../../Resources/config')); - $loader->load('nested_token_loaders.yml'); - foreach ($configs[$this->name()] as $name => $itemConfig) { $service_id = sprintf('jose.nested_token_loader.%s', $name); $definition = new Definition(self::class); @@ -72,82 +61,77 @@ public function load(array $configs, ContainerBuilder $container) public function getNodeDefinition(NodeDefinition $node) { - if (!$this->isEnabled()) { - return; - } - $node - ->children() - ->arrayNode($this->name()) - ->treatNullLike([]) - ->treatFalseLike([]) - ->useAttributeAsKey('name') - ->arrayPrototype() - ->children() - ->booleanNode('is_public') - ->info('If true, the service will be public, else private.') - ->defaultTrue() - ->end() - ->arrayNode('signature_algorithms') - ->info('A list of signature algorithm aliases.') - ->useAttributeAsKey('name') - ->isRequired() - ->scalarPrototype()->end() - ->end() - ->arrayNode('key_encryption_algorithms') - ->info('A list of key encryption algorithm aliases.') - ->useAttributeAsKey('name') - ->isRequired() - ->scalarPrototype()->end() - ->end() - ->arrayNode('content_encryption_algorithms') - ->info('A list of key encryption algorithm aliases.') - ->useAttributeAsKey('name') - ->isRequired() - ->scalarPrototype()->end() - ->end() - ->arrayNode('compression_methods') - ->info('A list of compression method aliases.') - ->useAttributeAsKey('name') - ->defaultValue(['DEF']) - ->scalarPrototype()->end() - ->end() - ->arrayNode('jws_serializers') - ->info('A list of JWS serializer aliases.') - ->useAttributeAsKey('name') - ->treatNullLike([]) - ->treatFalseLike([]) - ->requiresAtLeastOneElement() - ->scalarPrototype()->end() - ->end() - ->arrayNode('jwe_serializers') - ->info('A list of JWE serializer aliases.') - ->useAttributeAsKey('name') - ->treatNullLike([]) - ->treatFalseLike([]) - ->requiresAtLeastOneElement() - ->scalarPrototype()->end() - ->end() - ->arrayNode('jws_header_checkers') - ->info('A list of header checker aliases.') - ->useAttributeAsKey('name') - ->treatNullLike([]) - ->treatFalseLike([]) - ->scalarPrototype()->end() - ->end() - ->arrayNode('jwe_header_checkers') - ->info('A list of header checker aliases.') - ->useAttributeAsKey('name') - ->treatNullLike([]) - ->treatFalseLike([]) - ->scalarPrototype()->end() - ->end() - ->arrayNode('tags') - ->info('A list of tags to be associated to the service.') - ->useAttributeAsKey('name') - ->treatNullLike([]) - ->treatFalseLike([]) - ->variablePrototype()->end() - ->end() + $node->children() + ->arrayNode($this->name()) + ->treatNullLike([]) + ->treatFalseLike([]) + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->booleanNode('is_public') + ->info('If true, the service will be public, else private.') + ->defaultTrue() + ->end() + ->arrayNode('signature_algorithms') + ->info('A list of signature algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('key_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('content_encryption_algorithms') + ->info('A list of key encryption algorithm aliases.') + ->useAttributeAsKey('name') + ->isRequired() + ->scalarPrototype()->end() + ->end() + ->arrayNode('compression_methods') + ->info('A list of compression method aliases.') + ->useAttributeAsKey('name') + ->defaultValue(['DEF']) + ->scalarPrototype()->end() + ->end() + ->arrayNode('jws_serializers') + ->info('A list of JWS serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('jwe_serializers') + ->info('A list of JWE serializer aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->requiresAtLeastOneElement() + ->scalarPrototype()->end() + ->end() + ->arrayNode('jws_header_checkers') + ->info('A list of header checker aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->scalarPrototype()->end() + ->end() + ->arrayNode('jwe_header_checkers') + ->info('A list of header checker aliases.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->scalarPrototype()->end() + ->end() + ->arrayNode('tags') + ->info('A list of tags to be associated to the service.') + ->useAttributeAsKey('name') + ->treatNullLike([]) + ->treatFalseLike([]) + ->variablePrototype()->end() ->end() ->end() ->end() @@ -161,14 +145,4 @@ public function prepend(ContainerBuilder $container, array $config): array { return []; } - - /** - * @return bool - */ - private function isEnabled(): bool - { - return class_exists(JWEDecrypterFactory::class) - && class_exists(JWSVerifierFactory::class) - && class_exists(HeaderCheckerManagerFactory::class); - } } diff --git a/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php b/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php index fa9e76c6..14d5bb62 100644 --- a/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php +++ b/src/Bundle/JoseFramework/Helper/ConfigurationHelper.php @@ -144,24 +144,62 @@ public static function addNestedTokenLoader(ContainerBuilder $container, string { $config = [ self::BUNDLE_ALIAS => [ - 'nested_token_loaders' => [ - $name => [ - 'is_public' => $is_public, - 'jwe_serializers' => $jwe_serializers, - 'key_encryption_algorithms' => $key_encryption_algorithms, - 'content_encryption_algorithms' => $content_encryption_algorithms, - 'compression_methods' => $compression_methods, - 'jwe_header_checkers' => $jwe_header_checkers, - 'jws_serializers' => $jws_serializers, - 'signature_algorithms' => $signature_algorithms, - 'jws_header_checkers' => $jws_header_checkers, - 'tags' => $tags, + 'nested_token' => [ + 'loaders' => [ + $name => [ + 'is_public' => $is_public, + 'jwe_serializers' => $jwe_serializers, + 'key_encryption_algorithms' => $key_encryption_algorithms, + 'content_encryption_algorithms' => $content_encryption_algorithms, + 'compression_methods' => $compression_methods, + 'jwe_header_checkers' => $jwe_header_checkers, + 'jws_serializers' => $jws_serializers, + 'signature_algorithms' => $signature_algorithms, + 'jws_header_checkers' => $jws_header_checkers, + 'tags' => $tags, + ], + ], + ], + ], + ]; + + self::updateJoseConfiguration($container, $config, 'nested_token'); + } + + /** + * @param ContainerBuilder $container + * @param string $name + * @param string[] $jwe_serializers + * @param string[] $key_encryption_algorithms + * @param string[] $content_encryption_algorithms + * @param string[] $compression_methods + * @param string[] $jws_serializers + * @param string[] $signature_algorithms + * @param bool $is_public + * @param array $tags + */ + public static function addNestedTokenBuilder(ContainerBuilder $container, string $name, array $jwe_serializers, array $key_encryption_algorithms, array $content_encryption_algorithms, array $compression_methods, array $jws_serializers, array $signature_algorithms, bool $is_public = true, array $tags = []) + { + $config = [ + self::BUNDLE_ALIAS => [ + 'nested_token' => [ + 'builders' => [ + $name => [ + 'is_public' => $is_public, + 'jwe_serializers' => $jwe_serializers, + 'key_encryption_algorithms' => $key_encryption_algorithms, + 'content_encryption_algorithms' => $content_encryption_algorithms, + 'compression_methods' => $compression_methods, + 'jws_serializers' => $jws_serializers, + 'signature_algorithms' => $signature_algorithms, + 'tags' => $tags, + ], ], ], ], ]; - self::updateJoseConfiguration($container, $config, 'nested_token_loaders'); + self::updateJoseConfiguration($container, $config, 'nested_token'); } /** diff --git a/src/Bundle/JoseFramework/JoseFrameworkBundle.php b/src/Bundle/JoseFramework/JoseFrameworkBundle.php index 490f7856..44023785 100644 --- a/src/Bundle/JoseFramework/JoseFrameworkBundle.php +++ b/src/Bundle/JoseFramework/JoseFrameworkBundle.php @@ -73,7 +73,7 @@ private function getSources(): array new Source\Console\ConsoleSource(), new Source\Signature\SignatureSource(), new Source\Encryption\EncryptionSource(), - new Source\Encryption\NestedTokenLoader(), + new Source\Encryption\NestedToken(), new Source\KeyManagement\KeyManagementSource(), ]; } diff --git a/src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml b/src/Bundle/JoseFramework/Resources/config/nested_token.yml similarity index 72% rename from src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml rename to src/Bundle/JoseFramework/Resources/config/nested_token.yml index 0f2f411e..76b3d1f0 100644 --- a/src/Bundle/JoseFramework/Resources/config/nested_token_loaders.yml +++ b/src/Bundle/JoseFramework/Resources/config/nested_token.yml @@ -5,3 +5,4 @@ services: public: true Jose\Component\Encryption\NestedTokenLoaderFactory: ~ + Jose\Component\Encryption\NestedTokenBuilderFactory: ~ diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php new file mode 100644 index 00000000..45565fde --- /dev/null +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php @@ -0,0 +1,200 @@ +markTestSkipped('The component "web-token/jwt-encryption" is not installed.'); + } + if (!class_exists(JWSBuilderFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + if (!class_exists(HeaderCheckerManagerFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + } + + /** + * {@inheritdoc} + */ + protected function getConfiguration() + { + return new Configuration('jose', [ + new Source\Core\CoreSource(), + new Source\Checker\CheckerSource(), + new Source\Signature\SignatureSource(), + new Source\Encryption\EncryptionSource(), + new Source\Encryption\NestedToken(), + ]); + } + + /** + * @test + */ + public function theConfigurationIsValidIfNoConfigurationIsSet() + { + $this->assertConfigurationIsValid( + [] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfConfigurationIsFalse() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token' => false, + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfConfigurationIsEmpty() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token' => [], + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfNoBuilderIsSet() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token' => [ + 'builders' => [], + ], + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoSignatureAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [], + ], + ], + ], + ], + 'The child node "signature_algorithms" at path "jose.nested_token.builders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoKeyEncryptionAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + ], + ], + ], + ], + ], + 'The child node "key_encryption_algorithms" at path "jose.nested_token.builders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + ], + ], + ], + ], + ], + 'The child node "content_encryption_algorithms" at path "jose.nested_token.builders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsValid() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + ], + ], + ], + ], + ] + ); + } +} diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php new file mode 100644 index 00000000..32a5f541 --- /dev/null +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php @@ -0,0 +1,142 @@ +markTestSkipped('The component "web-token/jwt-encryption" is not installed.'); + } + if (!class_exists(JWSBuilderFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + if (!class_exists(HeaderCheckerManagerFactory::class)) { + $this->markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + } + + /** + * @test + */ + public function theNestedTokenBuilderFactoryIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has(NestedTokenBuilderFactory::class)); + } + + /** + * @test + */ + public function theNestedTokenBuilderFromTheConfigurationIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has('jose.nested_token_builder.nested_token_builder_1')); + } + + /** + * @test + */ + public function theNestedTokenBuilderFromTheConfigurationHelperIsAvailable() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + self::assertTrue($container->has('jose.nested_token_builder.nested_token_builder_2')); + } + + /** + * @test + */ + public function aNestedTokenCanBeSignedAndEncrypted() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + + /** @var NestedTokenBuilder $builder */ + $builder = $container->get('jose.nested_token_builder.nested_token_builder_2'); + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + + $token = $builder->create( + $payload, + [[ + 'key' => $signature_key, + 'protected_header' => ['alg' => 'PS256'], + 'header' => [], + ]], + 'jws_compact', + ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], + [], + [[ + 'key' => $encryption_key, + 'header' => [], + ]], + 'jwe_compact' + ); + + self::assertTrue(true); + } +} diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php index e0063c6c..7c69f14a 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php @@ -56,7 +56,7 @@ protected function getConfiguration() new Source\Checker\CheckerSource(), new Source\Signature\SignatureSource(), new Source\Encryption\EncryptionSource(), - new Source\Encryption\NestedTokenLoader(), + new Source\Encryption\NestedToken(), ]); } @@ -78,7 +78,7 @@ public function theConfigurationIsValidIfConfigurationIsFalse() $this->assertConfigurationIsValid( [ [ - 'nested_token_loaders' => false, + 'nested_token' => false, ], ] ); @@ -92,7 +92,23 @@ public function theConfigurationIsValidIfConfigurationIsEmpty() $this->assertConfigurationIsValid( [ [ - 'nested_token_loaders' => [], + 'nested_token' => [], + ], + ] + ); + } + + /** + * @test + */ + public function theConfigurationIsValidIfNoLoaderIsSet() + { + $this->assertConfigurationIsValid( + [ + [ + 'nested_token' => [ + 'loaders' => [], + ], ], ] ); @@ -106,12 +122,14 @@ public function theConfigurationIsInvalidIfNoSignatureAlgorithmIsSet() $this->assertConfigurationIsInvalid( [ [ - 'nested_token_loaders' => [ - 'foo' => [], + 'nested_token' => [ + 'loaders' => [ + 'foo' => [], + ], ], ], ], - 'The child node "signature_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + 'The child node "signature_algorithms" at path "jose.nested_token.loaders.foo" must be configured.' ); } @@ -123,14 +141,16 @@ public function theConfigurationIsInvalidIfNoKeyEncryptionAlgorithmIsSet() $this->assertConfigurationIsInvalid( [ [ - 'nested_token_loaders' => [ - 'foo' => [ - 'signature_algorithms' => ['RS256'], + 'nested_token' => [ + 'loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + ], ], ], ], ], - 'The child node "key_encryption_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + 'The child node "key_encryption_algorithms" at path "jose.nested_token.loaders.foo" must be configured.' ); } @@ -142,15 +162,17 @@ public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() $this->assertConfigurationIsInvalid( [ [ - 'nested_token_loaders' => [ - 'foo' => [ - 'signature_algorithms' => ['RS256'], - 'key_encryption_algorithms' => ['RSA-OAEP'], + 'nested_token' => [ + 'loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + ], ], ], ], ], - 'The child node "content_encryption_algorithms" at path "jose.nested_token_loaders.foo" must be configured.' + 'The child node "content_encryption_algorithms" at path "jose.nested_token.loaders.foo" must be configured.' ); } @@ -162,11 +184,13 @@ public function theConfigurationIsValid() $this->assertConfigurationIsValid( [ [ - 'nested_token_loaders' => [ - 'foo' => [ - 'signature_algorithms' => ['RS256'], - 'key_encryption_algorithms' => ['RSA-OAEP'], - 'content_encryption_algorithms' => ['A128GCM'], + 'nested_token' => [ + 'loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + ], ], ], ], diff --git a/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php b/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php index 2320a1c4..b16cdf22 100644 --- a/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php +++ b/src/Bundle/JoseFramework/Tests/TestBundle/DependencyInjection/TestExtension.php @@ -63,5 +63,6 @@ public function prepend(ContainerBuilder $container) ConfigurationHelper::addJWESerializer($container, 'jwe_serializer2', ['jwe_compact', 'jwe_json_flattened', 'jwe_json_general'], true); ConfigurationHelper::addJWELoader($container, 'jwe_loader2', ['jwe_compact'], ['RSA-OAEP-256'], ['A128GCM'], ['DEF'], [], true); ConfigurationHelper::addNestedTokenLoader($container, 'nested_token_loader_2', ['jwe_compact'], ['RSA-OAEP'], ['A128GCM'], ['DEF'], [], ['jws_compact'], ['PS256'], [], true, []); + ConfigurationHelper::addNestedTokenBuilder($container, 'nested_token_builder_2', ['jwe_compact'], ['RSA-OAEP'], ['A128GCM'], ['DEF'], ['jws_compact'], ['PS256'], true, []); } } diff --git a/src/Bundle/JoseFramework/Tests/config/config_test.yml b/src/Bundle/JoseFramework/Tests/config/config_test.yml index c1b0f556..cf6e4c7f 100644 --- a/src/Bundle/JoseFramework/Tests/config/config_test.yml +++ b/src/Bundle/JoseFramework/Tests/config/config_test.yml @@ -74,12 +74,19 @@ jose: content_encryption_algorithms: ['A256CBC-HS512'] compression_methods: [] is_public: true - nested_token_loaders: - nested_token_loader_1: - signature_algorithms: ['PS256'] - key_encryption_algorithms: ['RSA-OAEP'] - content_encryption_algorithms: ['A128GCM'] - is_public: true + nested_token: + loaders: + nested_token_loader_1: + signature_algorithms: ['PS256'] + key_encryption_algorithms: ['RSA-OAEP'] + content_encryption_algorithms: ['A128GCM'] + is_public: true + builders: + nested_token_builder_1: + signature_algorithms: ['PS256'] + key_encryption_algorithms: ['RSA-OAEP'] + content_encryption_algorithms: ['A128GCM'] + is_public: true keys: jwk1: jwk: diff --git a/src/Component/Encryption/NestedTokenBuilder.php b/src/Component/Encryption/NestedTokenBuilder.php new file mode 100644 index 00000000..90036e1f --- /dev/null +++ b/src/Component/Encryption/NestedTokenBuilder.php @@ -0,0 +1,102 @@ +jweBuilder = $jweBuilder; + $this->jwsSerializerManager = $jwsSerializerManager; + $this->jwsBuilder = $jwsBuilder; + $this->jweSerializerManager = $jweSerializerManager; + } + + /** + * @param string $payload + * @param array[] $signatures + * @param string $jws_serialization_mode + * @param array $jweSharedProtectedHeader + * @param array $jweSharedHeader + * @param array[] $recipients + * @param string $jwe_serialization_mode + * + * @return string + * + * @throws \Exception + */ + public function create(string $payload, array $signatures, string $jws_serialization_mode, array $jweSharedProtectedHeader, array $jweSharedHeader, array $recipients, string $jwe_serialization_mode): string + { + $jws = $this->jwsBuilder->create()->withPayload($payload); + foreach ($signatures as $signature) { + if (!is_array($signature) || !array_key_exists('key', $signature) || !array_key_exists('protected_header', $signature) || !array_key_exists('header', $signature)) { + throw new \InvalidArgumentException('The signatures must be an array of arrays containing a key, a protected header and a header'); + } + $jws = $jws->addSignature($signature['key'], $signature['protected_header'], $signature['header']); + } + $jws = $jws->build(); + $token = $this->jwsSerializerManager->serialize($jws_serialization_mode, $jws); + + $jweSharedProtectedHeader['cty'] = 'JWT'; + + $jwe = $this->jweBuilder + ->create() + ->withPayload($token) + ->withSharedProtectedHeader($jweSharedProtectedHeader) + ->withSharedHeader($jweSharedHeader) + ; + foreach ($recipients as $recipient) { + if (!is_array($recipient) || !array_key_exists('key', $recipient) || !array_key_exists('header', $recipient)) { + throw new \InvalidArgumentException('The recipients must be an array of arrays containing a key and a header'); + } + $jwe = $jwe->addRecipient($recipient['key'], $recipient['header']); + } + $jwe = $jwe->build(); + $token = $this->jweSerializerManager->serialize($jwe_serialization_mode, $jwe); + + return $token; + } +} diff --git a/src/Component/Encryption/NestedTokenBuilderFactory.php b/src/Component/Encryption/NestedTokenBuilderFactory.php new file mode 100644 index 00000000..e18d3333 --- /dev/null +++ b/src/Component/Encryption/NestedTokenBuilderFactory.php @@ -0,0 +1,77 @@ +jweBuilderFactory = $jweBuilderFactory; + $this->jweSerializerManagerFactory = $jweSerializerManagerFactory; + $this->jwsBuilderFactory = $jwsBuilderFactory; + $this->jwsSerializerManagerFactory = $jwsSerializerManagerFactory; + } + + /** + * @param array $jwe_serializers + * @param array $keyEncryptionAlgorithms + * @param array $contentEncryptionAlgorithms + * @param array $compressionMethods + * @param array $jws_serializers + * @param array $signatureAlgorithms + * + * @return NestedTokenBuilder + */ + public function create(array $jwe_serializers, array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithms, array $compressionMethods, array $jws_serializers, array $signatureAlgorithms): NestedTokenBuilder + { + $jweBuilder = $this->jweBuilderFactory->create($keyEncryptionAlgorithms, $contentEncryptionAlgorithms, $compressionMethods); + $jweSerializerManager = $this->jweSerializerManagerFactory->create($jwe_serializers); + $jwsBuilder = $this->jwsBuilderFactory->create($signatureAlgorithms); + $jwsSerializerManager = $this->jwsSerializerManagerFactory->create($jws_serializers); + + return new NestedTokenBuilder($jweBuilder, $jweSerializerManager, $jwsBuilder, $jwsSerializerManager); + } +} diff --git a/src/Component/Encryption/NestedTokenLoaderFactory.php b/src/Component/Encryption/NestedTokenLoaderFactory.php index 84f443da..14d48267 100644 --- a/src/Component/Encryption/NestedTokenLoaderFactory.php +++ b/src/Component/Encryption/NestedTokenLoaderFactory.php @@ -39,6 +39,18 @@ public function __construct(JWELoaderFactory $jweLoaderFactory, JWSLoaderFactory $this->jwsLoaderFactory = $jwsLoaderFactory; } + /** + * @param array $jweSerializers + * @param array $keyEncryptionAlgorithms + * @param array $contentEncryptionAlgorithms + * @param array $compressionMethods + * @param array $jweHeaderCheckers + * @param array $jwsSerializers + * @param array $signatureAlgorithms + * @param array $jwsHeaderCheckers + * + * @return NestedTokenLoader + */ public function create(array $jweSerializers, array $keyEncryptionAlgorithms, array $contentEncryptionAlgorithms, array $compressionMethods, array $jweHeaderCheckers, array $jwsSerializers, array $signatureAlgorithms, array $jwsHeaderCheckers): NestedTokenLoader { $jweLoader = $this->jweLoaderFactory->create($jweSerializers, $keyEncryptionAlgorithms, $contentEncryptionAlgorithms, $compressionMethods, $jweHeaderCheckers); diff --git a/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php new file mode 100644 index 00000000..97053e32 --- /dev/null +++ b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php @@ -0,0 +1,250 @@ +markTestSkipped('The component "web-token/jwt-checker" is not installed.'); + } + if (!class_exists(JWSBuilder::class)) { + $this->markTestSkipped('The component "web-token/jwt-signature" is not installed.'); + } + } + + public function testDecryption() + { + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + + $nestedTokenBuilder = $this->getNestedTokenBuilderFactory()->create( + ['jwe_compact'], + ['RSA-OAEP'], + ['A128GCM'], + ['DEF'], + ['jws_compact'], + ['PS256'] + ); + + $nestedTokenBuilder->create( + $payload, + [ + ['key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], 'header' => []] + ], + 'jws_compact', + ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], + [], + [ + ['key' => $encryption_key, 'header' => []] + ], + 'jwe_compact' + ); + + self::assertTrue(true); + } + + /** + * @var JWSBuilderFactory + */ + private $jwsBuilderFactory; + + /** + * @return JWSBuilderFactory + */ + protected function getJWSBuilderFactory(): JWSBuilderFactory + { + if (null === $this->jwsBuilderFactory) { + $this->jwsBuilderFactory = new JWSBuilderFactory( + new StandardConverter(), + $this->getAlgorithmManagerFactory() + ); + } + + return $this->jwsBuilderFactory; + } + + /** + * @var JWEBuilderFactory + */ + private $jweBuilderFactory; + + /** + * @return JWEBuilderFactory + */ + protected function getJWEBuilderFactory(): JWEBuilderFactory + { + if (null === $this->jweBuilderFactory) { + $this->jweBuilderFactory = new JWEBuilderFactory( + new StandardConverter(), + $this->getAlgorithmManagerFactory(), + $this->getCompressionMethodManagerFactory() + ); + } + + return $this->jweBuilderFactory; + } + + /** + * @var NestedTokenBuilderFactory + */ + private $nestedTokenBuilderFactory; + + /** + * @return NestedTokenBuilderFactory + */ + private function getNestedTokenBuilderFactory(): NestedTokenBuilderFactory + { + if (null === $this->nestedTokenBuilderFactory) { + $this->nestedTokenBuilderFactory = new NestedTokenBuilderFactory( + $this->getJWEBuilderFactory(), + $this->getJWESerializerManagerFactory(), + $this->getJWSBuilderFactory(), + $this->getJWSSerializerManagerFactory() + ); + } + + return $this->nestedTokenBuilderFactory; + } + + /** + * @return JwsSerializer\JWSSerializerManagerFactory + */ + private function getJWSSerializerManagerFactory(): JwsSerializer\JWSSerializerManagerFactory + { + $jwsSerializerManagerFactory = new JwsSerializer\JWSSerializerManagerFactory(); + $jwsSerializerManagerFactory->add(new JwsSerializer\CompactSerializer(new StandardConverter())); + $jwsSerializerManagerFactory->add(new JwsSerializer\JSONFlattenedSerializer(new StandardConverter())); + $jwsSerializerManagerFactory->add(new JwsSerializer\JSONGeneralSerializer(new StandardConverter())); + + return $jwsSerializerManagerFactory; + } + + /** + * @var AlgorithmManagerFactory + */ + private $algorithmManagerFactory; + + /** + * @return AlgorithmManagerFactory + */ + private function getAlgorithmManagerFactory(): AlgorithmManagerFactory + { + if (null === $this->algorithmManagerFactory) { + $this->algorithmManagerFactory = new AlgorithmManagerFactory(); + $this->algorithmManagerFactory + ->add('A128GCM', new A128GCM()) + ->add('RSA-OAEP', new RSAOAEP()) + ->add('PS256', new PS256()); + } + + return $this->algorithmManagerFactory; + } + + /** + * @var CompressionMethodManagerFactory + */ + private $compressionMethodManagerFactory; + + /** + * @return CompressionMethodManagerFactory + */ + private function getCompressionMethodManagerFactory(): CompressionMethodManagerFactory + { + if (null === $this->compressionMethodManagerFactory) { + $this->compressionMethodManagerFactory = new CompressionMethodManagerFactory(); + $this->compressionMethodManagerFactory + ->add('DEF', new Compression\Deflate()) + ->add('ZLIB', new Compression\ZLib()) + ->add('GZ', new Compression\GZip()); + } + + return $this->compressionMethodManagerFactory; + } + + /** + * @var null|JweSerializer\JWESerializerManagerFactory + */ + private $jwsSerializerManagerFactory = null; + + /** + * @return JweSerializer\JWESerializerManagerFactory + */ + private function getJWESerializerManagerFactory(): JweSerializer\JWESerializerManagerFactory + { + if (null === $this->jwsSerializerManagerFactory) { + $this->jwsSerializerManagerFactory = new JweSerializer\JWESerializerManagerFactory(); + $this->jwsSerializerManagerFactory->add(new JweSerializer\CompactSerializer(new StandardConverter())); + $this->jwsSerializerManagerFactory->add(new JweSerializer\JSONFlattenedSerializer(new StandardConverter())); + $this->jwsSerializerManagerFactory->add(new JweSerializer\JSONGeneralSerializer(new StandardConverter())); + } + + return $this->jwsSerializerManagerFactory; + } +} From ef450e87b992dd4b9590d43f5d30fb50af973b7b Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 21:41:26 +0100 Subject: [PATCH 4/8] Apply fixes from StyleCI (#86) [ci skip] [skip ci] --- .../DependencyInjection/Source/Encryption/NestedToken.php | 1 + .../Tests/Functional/Encryption/NestedTokenBuilderTest.php | 7 +++---- src/Component/Encryption/NestedTokenBuilder.php | 7 +++---- .../Encryption/Tests/RFC7520/NestingTokenBuilderTest.php | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php index d33b0b61..c4f5693d 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedToken.php @@ -39,6 +39,7 @@ public function __construct() new NestedTokenBuilder(), ]; } + /** * {@inheritdoc} */ diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php index 32a5f541..9341b310 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php @@ -15,7 +15,6 @@ use Jose\Component\Checker\HeaderCheckerManagerFactory; use Jose\Component\Core\JWK; -use Jose\Component\Core\JWKSet; use Jose\Component\Encryption\JWEBuilderFactory; use Jose\Component\Encryption\NestedTokenBuilder; use Jose\Component\Encryption\NestedTokenBuilderFactory; @@ -123,15 +122,15 @@ public function aNestedTokenCanBeSignedAndEncrypted() $token = $builder->create( $payload, [[ - 'key' => $signature_key, + 'key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], - 'header' => [], + 'header' => [], ]], 'jws_compact', ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], [], [[ - 'key' => $encryption_key, + 'key' => $encryption_key, 'header' => [], ]], 'jwe_compact' diff --git a/src/Component/Encryption/NestedTokenBuilder.php b/src/Component/Encryption/NestedTokenBuilder.php index 90036e1f..b9349a19 100644 --- a/src/Component/Encryption/NestedTokenBuilder.php +++ b/src/Component/Encryption/NestedTokenBuilder.php @@ -64,9 +64,9 @@ public function __construct(JWEBuilder $jweBuilder, JWESerializerManager $jweSer * @param array[] $recipients * @param string $jwe_serialization_mode * - * @return string - * * @throws \Exception + * + * @return string */ public function create(string $payload, array $signatures, string $jws_serialization_mode, array $jweSharedProtectedHeader, array $jweSharedHeader, array $recipients, string $jwe_serialization_mode): string { @@ -86,8 +86,7 @@ public function create(string $payload, array $signatures, string $jws_serializa ->create() ->withPayload($token) ->withSharedProtectedHeader($jweSharedProtectedHeader) - ->withSharedHeader($jweSharedHeader) - ; + ->withSharedHeader($jweSharedHeader); foreach ($recipients as $recipient) { if (!is_array($recipient) || !array_key_exists('key', $recipient) || !array_key_exists('header', $recipient)) { throw new \InvalidArgumentException('The recipients must be an array of arrays containing a key and a header'); diff --git a/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php index 97053e32..d0dabb25 100644 --- a/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php +++ b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php @@ -96,13 +96,13 @@ public function testDecryption() $nestedTokenBuilder->create( $payload, [ - ['key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], 'header' => []] + ['key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], 'header' => []], ], 'jws_compact', ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], [], [ - ['key' => $encryption_key, 'header' => []] + ['key' => $encryption_key, 'header' => []], ], 'jwe_compact' ); From bab53bc1ab90359e0dd61bd2df3c218b18093957 Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 22:11:31 +0100 Subject: [PATCH 5/8] Configuration fixed --- .../Source/Encryption/NestedTokenBuilder.php | 2 + .../Source/Encryption/NestedTokenLoader.php | 2 + .../NestedTokenBuilderConfigurationTest.php | 49 ++++++++++++++ .../Encryption/NestedTokenBuilderTest.php | 65 ++++++++++++++++++- .../NestedTokenLoaderConfigurationTest.php | 49 ++++++++++++++ .../Encryption/NestedTokenLoaderTest.php | 55 +++++++++++++++- .../Tests/config/config_test.yml | 4 ++ 7 files changed, 224 insertions(+), 2 deletions(-) diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php index 649e6651..797b615d 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenBuilder.php @@ -99,6 +99,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) + ->isRequired() ->requiresAtLeastOneElement() ->scalarPrototype()->end() ->end() @@ -107,6 +108,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) + ->isRequired() ->requiresAtLeastOneElement() ->scalarPrototype()->end() ->end() diff --git a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php index 0521cc89..f24585be 100644 --- a/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php +++ b/src/Bundle/JoseFramework/DependencyInjection/Source/Encryption/NestedTokenLoader.php @@ -101,6 +101,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) + ->isRequired() ->requiresAtLeastOneElement() ->scalarPrototype()->end() ->end() @@ -109,6 +110,7 @@ public function getNodeDefinition(NodeDefinition $node) ->useAttributeAsKey('name') ->treatNullLike([]) ->treatFalseLike([]) + ->isRequired() ->requiresAtLeastOneElement() ->scalarPrototype()->end() ->end() diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php index 45565fde..ddb18fd2 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderConfigurationTest.php @@ -176,6 +176,53 @@ public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() ); } + /** + * @test + */ + public function theConfigurationIsInvalidIfNoJwsSerializerIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + ], + ], + ], + ], + ], + 'The child node "jws_serializers" at path "jose.nested_token.builders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoJweSerializerIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'builders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + 'jws_serializers' => ['jws_compact'], + ], + ], + ], + ], + ], + 'The child node "jwe_serializers" at path "jose.nested_token.builders.foo" must be configured.' + ); + } + /** * @test */ @@ -190,6 +237,8 @@ public function theConfigurationIsValid() 'signature_algorithms' => ['RS256'], 'key_encryption_algorithms' => ['RSA-OAEP'], 'content_encryption_algorithms' => ['A128GCM'], + 'jws_serializers' => ['jws_compact'], + 'jwe_serializers' => ['jwe_compact'], ], ], ], diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php index 9341b310..c41e24aa 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php @@ -79,7 +79,70 @@ public function theNestedTokenBuilderFromTheConfigurationHelperIsAvailable() /** * @test */ - public function aNestedTokenCanBeSignedAndEncrypted() + public function aNestedTokenCanBeSignedAndEncryptedUsingTheServiceCreatedFromTheConfiguration() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + + /** @var NestedTokenBuilder $builder */ + $builder = $container->get('jose.nested_token_builder.nested_token_builder_1'); + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + + $token = $builder->create( + $payload, + [[ + 'key' => $signature_key, + 'protected_header' => ['alg' => 'PS256'], + 'header' => [], + ]], + 'jws_compact', + ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], + [], + [[ + 'key' => $encryption_key, + 'header' => [], + ]], + 'jwe_compact' + ); + + self::assertTrue(true); + } + + /** + * @test + */ + public function aNestedTokenCanBeSignedAndEncryptedUsingTheServiceCreatedFromTheConfigurationHelper() { $client = static::createClient(); $container = $client->getContainer(); diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php index 7c69f14a..ecf5290d 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderConfigurationTest.php @@ -176,6 +176,53 @@ public function theConfigurationIsInvalidIfNoContentEncryptionAlgorithmIsSet() ); } + /** + * @test + */ + public function theConfigurationIsInvalidIfNoJwsSerializerIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + ], + ], + ], + ], + ], + 'The child node "jws_serializers" at path "jose.nested_token.loaders.foo" must be configured.' + ); + } + + /** + * @test + */ + public function theConfigurationIsInvalidIfNoJweSerializerIsSet() + { + $this->assertConfigurationIsInvalid( + [ + [ + 'nested_token' => [ + 'loaders' => [ + 'foo' => [ + 'signature_algorithms' => ['RS256'], + 'key_encryption_algorithms' => ['RSA-OAEP'], + 'content_encryption_algorithms' => ['A128GCM'], + 'jws_serializers' => ['jws_compact'], + ], + ], + ], + ], + ], + 'The child node "jwe_serializers" at path "jose.nested_token.loaders.foo" must be configured.' + ); + } + /** * @test */ @@ -190,6 +237,8 @@ public function theConfigurationIsValid() 'signature_algorithms' => ['RS256'], 'key_encryption_algorithms' => ['RSA-OAEP'], 'content_encryption_algorithms' => ['A128GCM'], + 'jws_serializers' => ['jws_compact'], + 'jwe_serializers' => ['jwe_compact'], ], ], ], diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php index 022998d3..0128f68d 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenLoaderTest.php @@ -80,7 +80,60 @@ public function theNestedTokenLoaderFromTheConfigurationHelperIsAvailable() /** * @test */ - public function aNestedTokenCanBeDecryptedAndVerified() + public function aNestedTokenCanBeDecryptedAndVerifiedUsingTheServiceCreatedFromTheConfiguration() + { + $client = static::createClient(); + $container = $client->getContainer(); + self::assertNotNull($container); + + /** @var NestedTokenLoader $loader */ + $loader = $container->get('jose.nested_token_loader.nested_token_loader_1'); + + $encryption_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'samwise.gamgee@hobbiton.example', + 'use' => 'enc', + 'n' => 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + 'e' => 'AQAB', + 'alg' => 'RSA-OAEP', + 'd' => 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + 'p' => '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + 'q' => 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + 'dp' => '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + 'dq' => 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + 'qi' => 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + ]); + $encryption_key_set = JWKSet::createFromKeys([$encryption_key]); + + $signature_key = JWK::create([ + 'kty' => 'RSA', + 'kid' => 'hobbiton.example', + 'use' => 'sig', + 'n' => 'kNrPIBDXMU6fcyv5i-QHQAQ-K8gsC3HJb7FYhYaw8hXbNJa-t8q0lDKwLZgQXYV-ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s-hwx1IU5AT-AIelNqBgcF2vE5W25_SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8-lh4oVB07bkac6LQdHpJUUySH_Er20DXx30Kyi97PciXKTS-QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy-7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfw', + 'e' => 'AQAB', + 'd' => 'ZLe_TIxpE9-W_n2VBa-HWvuYPtjvxwVXClJFOpJsdea8g9RMx34qEOEtnoYc2un3CZ3LtJi-mju5RAT8YSc76YJds3ZVw0UiO8mMBeG6-iOnvgobobNx7K57-xjTJZU72EjOr9kB7z6ZKwDDq7HFyCDhUEcYcHFVc7iL_6TibVhAhOFONWlqlJgEgwVYd0rybNGKifdnpEbwyHoMwY6HM1qvnEFgP7iZ0YzHUT535x6jj4VKcdA7ZduFkhUauysySEW7mxZM6fj1vdjJIy9LD1fIz30Xv4ckoqhKF5GONU6tNmMmNgAD6gIViyEle1PrIxl1tBhCI14bRW-zrpHgAQ', + 'p' => 'yKWYoNIAqwMRQlgIBOdT1NIcbDNUUs2Rh-pBaxD_mIkweMt4Mg-0-B2iSYvMrs8horhonV7vxCQagcBAATGW-hAafUehWjxWSH-3KccRM8toL4e0q7M-idRDOBXSoe7Z2-CV2x_ZCY3RP8qp642R13WgXqGDIM4MbUkZSjcY9-c', + 'q' => 'uND4o15V30KDzf8vFJw589p1vlQVQ3NEilrinRUPHkkxaAzDzccGgrWMWpGxGFFnNL3w5CqPLeU76-5IVYQq0HwYVl0hVXQHr7sgaGu-483Ad3ENcL23FrOnF45m7_2ooAstJDe49MeLTTQKrSIBl_SKvqpYvfSPTczPcZkh9Kk', + 'dp' => 'jmTnEoq2qqa8ouaymjhJSCnsveUXnMQC2gAneQJRQkFqQu-zV2PKPKNbPvKVyiF5b2-L3tM3OW2d2iNDyRUWXlT7V5l0KwPTABSTOnTqAmYChGi8kXXdlhcrtSvXldBakC6saxwI_TzGGY2MVXzc2ZnCvCXHV4qjSxOrfP3pHFU', + 'dq' => 'R9FUvU88OVzEkTkXl3-5-WusE4DjHmndeZIlu3rifBdfLpq_P-iWPBbGaq9wzQ1c-J7SzCdJqkEJDv5yd2C7rnZ6kpzwBh_nmL8zscAk1qsunnt9CJGAYz7-sGWy1JGShFazfP52ThB4rlCJ0YuEaQMrIzpY77_oLAhpmDA0hLk', + 'qi' => 'S8tC7ZknW6hPITkjcwttQOPLVmRfwirRlFAViuDb8NW9CrV_7F2OqUZCqmzHTYAumwGFHI1WVRep7anleWaJjxC_1b3fq_al4qH3Pe-EKiHg6IMazuRtZLUROcThrExDbF5dYbsciDnfRUWLErZ4N1Be0bnxYuPqxwKd9QZwMo0', + ]); + $signature_key_set = JWKSet::createFromKeys([ + $signature_key, + ]); + + $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; + $token = 'eyJhbGciOiJSU0EtT0FFUCIsImN0eSI6IkpXVCIsImVuYyI6IkExMjhHQ00ifQ.a0JHRoITfpX4qRewImjlStn8m3CPxBV1ueYlVhjurCyrBg3I7YhCRYjphDOOS4E7rXbr2Fn6NyQq-A-gqT0FXqNjVOGrG-bi13mwy7RoYhjTkBEC6P7sMYMXXx4gzMedpiJHQVeyI-zkZV7A9matpgevAJWrXzOUysYGTtwoSN6gtUVtlLaivjvb21O0ul4YxSHV-ByK1kyeetRp_fuYJxHoKLQL9P424sKx2WGYb4zsBIPF4ssl_e5IR7nany-25_UmC2urosNkoFz9cQ82MypZP8gqbQJyPN-Fpp4Z-5o6yV64x6yzDUF_5JCIdl-Qv6H5dMVIY7q1eKpXcV1lWO_2FefEBqXxXvIjLeZivjNkzogCq3-IapSjVFnMjBxjpYLT8muaawo1yy1XXMuinIpNcOY3n4KKrXLrCcteX85m4IIHMZa38s1Hpr56fPPseMA-Jltmt-a9iEDtOzhtxz8AXy9tsCAZV2XBWNG8c3kJusAamBKOYwfk7JhLRDgOnJjlJLhn7TI4UxDp9dCmUXEN6z0v23W15qJIEXNJtqnblpymooeWAHCT4e_Owbim1g0AEpTHUdA2iiLNs9WTX_H_TXuPC8yDDhi1smxS_X_xpkIHkiIHWDOLx03BpqDTivpKkBYwqP2UZkcxqX2Fo_GnVrNwlK7Lgxw6FSQvDO0.GbX1i9kXz0sxXPmA.SZI4IvKHmwpazl_pJQXX3mHv1ANnOU4Wf9-utWYUcKrBNgCe2OFMf66cSJ8k2QkxaQD3_R60MGE9ofomwtky3GFxMeGRjtpMt9OAvVLsAXB0_UTCBGyBg3C2bWLXqZlfJAAoJRUPRk-BimYZY81zVBuIhc7HsQePCpu33SzMsFHjn4lP_idrJz_glZTNgKDt8zdnUPauKTKDNOH1DD4fuzvDYfDIAfqGPyL5sVRwbiXpXdGokEszM-9ChMPqW1QNhzuX_Zul3bvrJwr7nuGZs4cUScY3n8yE3AHCLurgls-A9mz1X38xEaulV18l4Fg9tLejdkAuQZjPbqeHQBJe4IwGD5Ee0dQ-Mtz4NnhkIWx-YKBb_Xo2zI3Q_1sYjKUuis7yWW-HTr_vqvFt0bj7WJf2vzB0TZ3dvsoGaTvPH2dyWwumUrlx4gmPUzBdwTO6ubfYSDUEEz5py0d_OtWeUSYcCYBKD-aM7tXg26qJo21gYjLfhn9zy-W19sOCZGuzgFjPhawXHpvnj_t-0_ES96kogjJLxS1IMU9Y5XmnwZMyNc9EIwnogsCg-hVuvzyP0sIruktmI94_SL1xgMl7o03phcTMxtlMizR88NKU1WkBsiXMCjy1Noue7MD-ShDp5dmM.KnIKEhN8U-3C9s4gtSpjSw'; + + $jws = $loader->load($token, $encryption_key_set, $signature_key_set, $signature); + self::assertEquals($payload, $jws->getPayload()); + self::assertEquals(0, $signature); + } + + /** + * @test + */ + public function aNestedTokenCanBeDecryptedAndVerifiedUsingTheServiceCreatedFromTheConfigurationHelper() { $client = static::createClient(); $container = $client->getContainer(); diff --git a/src/Bundle/JoseFramework/Tests/config/config_test.yml b/src/Bundle/JoseFramework/Tests/config/config_test.yml index cf6e4c7f..1fb22ecf 100644 --- a/src/Bundle/JoseFramework/Tests/config/config_test.yml +++ b/src/Bundle/JoseFramework/Tests/config/config_test.yml @@ -80,12 +80,16 @@ jose: signature_algorithms: ['PS256'] key_encryption_algorithms: ['RSA-OAEP'] content_encryption_algorithms: ['A128GCM'] + jws_serializers: ['jws_compact'] + jwe_serializers: ['jwe_compact'] is_public: true builders: nested_token_builder_1: signature_algorithms: ['PS256'] key_encryption_algorithms: ['RSA-OAEP'] content_encryption_algorithms: ['A128GCM'] + jws_serializers: ['jws_compact'] + jwe_serializers: ['jwe_compact'] is_public: true keys: jwk1: From 23551e66b31b02c1c0f4904ab8055a284e11492d Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 23:03:39 +0100 Subject: [PATCH 6/8] Nested Token Building improvments --- .../Functional/Encryption/NestedTokenBuilderTest.php | 8 ++------ src/Component/Encryption/NestedTokenBuilder.php | 7 +++++-- .../Encryption/Tests/RFC7520/NestingTokenBuilderTest.php | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php index c41e24aa..c210738d 100644 --- a/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php +++ b/src/Bundle/JoseFramework/Tests/Functional/Encryption/NestedTokenBuilderTest.php @@ -119,19 +119,17 @@ public function aNestedTokenCanBeSignedAndEncryptedUsingTheServiceCreatedFromThe $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; - $token = $builder->create( + $builder->create( $payload, [[ 'key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], - 'header' => [], ]], 'jws_compact', ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], [], [[ 'key' => $encryption_key, - 'header' => [], ]], 'jwe_compact' ); @@ -182,19 +180,17 @@ public function aNestedTokenCanBeSignedAndEncryptedUsingTheServiceCreatedFromThe $payload = '{"iss":"hobbiton.example","exp":1300819380,"http://example.com/is_root":true}'; - $token = $builder->create( + $builder->create( $payload, [[ 'key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], - 'header' => [], ]], 'jws_compact', ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], [], [[ 'key' => $encryption_key, - 'header' => [], ]], 'jwe_compact' ); diff --git a/src/Component/Encryption/NestedTokenBuilder.php b/src/Component/Encryption/NestedTokenBuilder.php index b9349a19..496025b4 100644 --- a/src/Component/Encryption/NestedTokenBuilder.php +++ b/src/Component/Encryption/NestedTokenBuilder.php @@ -72,9 +72,11 @@ public function create(string $payload, array $signatures, string $jws_serializa { $jws = $this->jwsBuilder->create()->withPayload($payload); foreach ($signatures as $signature) { - if (!is_array($signature) || !array_key_exists('key', $signature) || !array_key_exists('protected_header', $signature) || !array_key_exists('header', $signature)) { + if (!is_array($signature) || !array_key_exists('key', $signature)) { throw new \InvalidArgumentException('The signatures must be an array of arrays containing a key, a protected header and a header'); } + $signature['protected_header'] = array_key_exists('protected_header', $signature) ? $signature['protected_header'] : []; + $signature['header'] = array_key_exists('header', $signature) ? $signature['header'] : []; $jws = $jws->addSignature($signature['key'], $signature['protected_header'], $signature['header']); } $jws = $jws->build(); @@ -88,9 +90,10 @@ public function create(string $payload, array $signatures, string $jws_serializa ->withSharedProtectedHeader($jweSharedProtectedHeader) ->withSharedHeader($jweSharedHeader); foreach ($recipients as $recipient) { - if (!is_array($recipient) || !array_key_exists('key', $recipient) || !array_key_exists('header', $recipient)) { + if (!is_array($recipient) || !array_key_exists('key', $recipient)) { throw new \InvalidArgumentException('The recipients must be an array of arrays containing a key and a header'); } + $recipient['header'] = array_key_exists('header', $recipient) ? $recipient['header'] : []; $jwe = $jwe->addRecipient($recipient['key'], $recipient['header']); } $jwe = $jwe->build(); diff --git a/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php index d0dabb25..98c8c2f4 100644 --- a/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php +++ b/src/Component/Encryption/Tests/RFC7520/NestingTokenBuilderTest.php @@ -96,13 +96,13 @@ public function testDecryption() $nestedTokenBuilder->create( $payload, [ - ['key' => $signature_key, 'protected_header' => ['alg' => 'PS256'], 'header' => []], + ['key' => $signature_key, 'protected_header' => ['alg' => 'PS256']], ], 'jws_compact', ['alg' => 'RSA-OAEP', 'enc' => 'A128GCM'], [], [ - ['key' => $encryption_key, 'header' => []], + ['key' => $encryption_key], ], 'jwe_compact' ); From 9568eda9a7d40d62dc6c8a4de8f22eb8da5ad8ac Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 23:10:36 +0100 Subject: [PATCH 7/8] AAD support --- .../Encryption/NestedTokenBuilder.php | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Component/Encryption/NestedTokenBuilder.php b/src/Component/Encryption/NestedTokenBuilder.php index 496025b4..79375672 100644 --- a/src/Component/Encryption/NestedTokenBuilder.php +++ b/src/Component/Encryption/NestedTokenBuilder.php @@ -56,19 +56,20 @@ public function __construct(JWEBuilder $jweBuilder, JWESerializerManager $jweSer } /** - * @param string $payload - * @param array[] $signatures - * @param string $jws_serialization_mode - * @param array $jweSharedProtectedHeader - * @param array $jweSharedHeader - * @param array[] $recipients - * @param string $jwe_serialization_mode + * @param string $payload + * @param array[] $signatures + * @param string $jws_serialization_mode + * @param array $jweSharedProtectedHeader + * @param array $jweSharedHeader + * @param array[] $recipients + * @param string $jwe_serialization_mode + * @param string|null $aad * * @throws \Exception * * @return string */ - public function create(string $payload, array $signatures, string $jws_serialization_mode, array $jweSharedProtectedHeader, array $jweSharedHeader, array $recipients, string $jwe_serialization_mode): string + public function create(string $payload, array $signatures, string $jws_serialization_mode, array $jweSharedProtectedHeader, array $jweSharedHeader, array $recipients, string $jwe_serialization_mode, ?string $aad = null): string { $jws = $this->jwsBuilder->create()->withPayload($payload); foreach ($signatures as $signature) { @@ -88,7 +89,9 @@ public function create(string $payload, array $signatures, string $jws_serializa ->create() ->withPayload($token) ->withSharedProtectedHeader($jweSharedProtectedHeader) - ->withSharedHeader($jweSharedHeader); + ->withSharedHeader($jweSharedHeader) + ->withAAD($aad) + ; foreach ($recipients as $recipient) { if (!is_array($recipient) || !array_key_exists('key', $recipient)) { throw new \InvalidArgumentException('The recipients must be an array of arrays containing a key and a header'); From ce810b12f38be91c578b78bfbfa53b310638359b Mon Sep 17 00:00:00 2001 From: Spomky Date: Sat, 17 Feb 2018 23:10:59 +0100 Subject: [PATCH 8/8] Apply fixes from StyleCI (#87) [ci skip] [skip ci] --- src/Component/Encryption/NestedTokenBuilder.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Component/Encryption/NestedTokenBuilder.php b/src/Component/Encryption/NestedTokenBuilder.php index 79375672..85e5354d 100644 --- a/src/Component/Encryption/NestedTokenBuilder.php +++ b/src/Component/Encryption/NestedTokenBuilder.php @@ -90,8 +90,7 @@ public function create(string $payload, array $signatures, string $jws_serializa ->withPayload($token) ->withSharedProtectedHeader($jweSharedProtectedHeader) ->withSharedHeader($jweSharedHeader) - ->withAAD($aad) - ; + ->withAAD($aad); foreach ($recipients as $recipient) { if (!is_array($recipient) || !array_key_exists('key', $recipient)) { throw new \InvalidArgumentException('The recipients must be an array of arrays containing a key and a header');