diff --git a/CHANGELOG.md b/CHANGELOG.md index 6044b94..abefdba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.2 + +* Fix: add child node `rules` array config to avoid empty array when using arrayPrototype. + ## 1.0.1 * Fix: auto add authenticator when not config. \ No newline at end of file diff --git a/src/DependencyInjection/Security/AuthenticatorFactory.php b/src/DependencyInjection/Security/AuthenticatorFactory.php index 6bc01bb..df940b4 100644 --- a/src/DependencyInjection/Security/AuthenticatorFactory.php +++ b/src/DependencyInjection/Security/AuthenticatorFactory.php @@ -31,7 +31,7 @@ public function createAuthenticator( ) { $authenticator = sprintf('security.authenticator.istio_jwt_authenticator.%s', $firewallName); $definition = new ChildDefinition('istio.jwt_authentication.authenticator'); - $definition->replaceArgument(0, $this->createUserIdentifierClaimMappings($container, $authenticator, $config)); + $definition->replaceArgument(0, $this->createUserIdentifierClaimMappings($container, $authenticator, $config['rules'])); $definition->replaceArgument(1, new Reference($userProviderId)); $container->setDefinition($authenticator, $definition); @@ -61,33 +61,40 @@ public function getKey() public function addConfiguration(NodeDefinition $builder) { $builder - ->fixXmlConfig('origin_token_header') - ->fixXmlConfig('origin_token_query_param') - ->fixXmlConfig('base64_header') - ->arrayPrototype() - ->addDefaultsIfNotSet() - ->children() - ->scalarNode('issuer') - ->cannotBeEmpty() - ->isRequired() - ->end() - ->scalarNode('user_identifier_claim') - ->cannotBeEmpty() - ->defaultValue('sub') - ->end() - ->arrayNode('origin_token_headers') - ->scalarPrototype() - ->cannotBeEmpty() - ->end() - ->end() - ->arrayNode('origin_token_query_params') - ->scalarPrototype() - ->cannotBeEmpty() - ->end() - ->end() - ->arrayNode('base64_headers') - ->scalarPrototype() - ->cannotBeEmpty() + ->fixXmlConfig('rule') + ->children() + ->arrayNode('rules') + ->isRequired() + ->cannotBeEmpty() + ->arrayPrototype() + ->fixXmlConfig('origin_token_header') + ->fixXmlConfig('origin_token_query_param') + ->fixXmlConfig('base64_header') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('issuer') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->scalarNode('user_identifier_claim') + ->cannotBeEmpty() + ->defaultValue('sub') + ->end() + ->arrayNode('origin_token_headers') + ->scalarPrototype() + ->cannotBeEmpty() + ->end() + ->end() + ->arrayNode('origin_token_query_params') + ->scalarPrototype() + ->cannotBeEmpty() + ->end() + ->end() + ->arrayNode('base64_headers') + ->scalarPrototype() + ->cannotBeEmpty() + ->end() + ->end() ->end() ->end() ->end() @@ -97,42 +104,42 @@ public function addConfiguration(NodeDefinition $builder) private function createUserIdentifierClaimMappings( ContainerBuilder $container, - string $authenticatorName, - array $config, + string $authenticatorId, + array $rules, ): IteratorArgument { - $extractorIdPrefix = sprintf('%s.payload_extractor', $authenticatorName); + $extractorIdPrefix = sprintf('%s.payload_extractor', $authenticatorId); $mappings = []; - foreach ($config as $key => $item) { + foreach ($rules as $key => $rule) { $extractor = null; - if (!empty($item['origin_token_headers'])) { + if (!empty($rule['origin_token_headers'])) { $extractor = $this->createPayloadExtractor( $container, sprintf('%s.origin_token_headers.%s', $extractorIdPrefix, $key), 'istio.jwt_authentication.payload_extractor.origin_token.header', - $item['issuer'], - $item['origin_token_headers'] + $rule['issuer'], + $rule['origin_token_headers'] ); } - if (!empty($item['origin_token_query_params'])) { + if (!empty($rule['origin_token_query_params'])) { $extractor = $this->createPayloadExtractor( $container, sprintf('%s.origin_token_query_params.%s', $extractorIdPrefix, $key), 'istio.jwt_authentication.payload_extractor.origin_token.query_param', - $item['issuer'], - $item['origin_token_query_params'] + $rule['issuer'], + $rule['origin_token_query_params'] ); } - if (!empty($item['base64_headers'])) { + if (!empty($rule['base64_headers'])) { $extractor = $this->createPayloadExtractor( $container, sprintf('%s.base64_headers.%s', $extractorIdPrefix, $key), 'istio.jwt_authentication.payload_extractor.base64_header', - $item['issuer'], - $item['base64_headers'] + $rule['issuer'], + $rule['base64_headers'] ); } @@ -140,10 +147,10 @@ private function createUserIdentifierClaimMappings( throw new InvalidConfigurationException(sprintf('`%s`: at least once `origin_token_headers`, `origin_token_query_params`, `base64_headers` should be config when using', $this->getKey())); } - $mappingId = sprintf('%s.user_identifier_claim_mapping.%s', $authenticatorName, $key); + $mappingId = sprintf('%s.user_identifier_claim_mapping.%s', $authenticatorId, $key); $mappings[] = new Reference($mappingId); $mappingDefinition = new Definition(UserIdentifierClaimMapping::class); - $mappingDefinition->setArgument(0, $item['user_identifier_claim']); + $mappingDefinition->setArgument(0, $rule['user_identifier_claim']); $mappingDefinition->setArgument(1, $extractor); $container->setDefinition($mappingId, $mappingDefinition); } diff --git a/tests/TestKernel.php b/tests/TestKernel.php index d8a3d8d..0b344c1 100644 --- a/tests/TestKernel.php +++ b/tests/TestKernel.php @@ -68,15 +68,17 @@ function (ContainerBuilder $container) { 'provider' => 'istio', 'stateless' => true, 'istio_jwt_authenticator' => [ - [ - 'issuer' => 'issuer_1', - 'user_identifier_claim' => 'id_1', - 'origin_token_query_params' => ['token'], - ], - [ - 'issuer' => 'issuer_2', - 'user_identifier_claim' => 'id_2', - 'base64_headers' => ['x-istio-jwt-payload'], + 'rules' => [ + [ + 'issuer' => 'issuer_1', + 'user_identifier_claim' => 'id_1', + 'origin_token_query_params' => ['token'], + ], + [ + 'issuer' => 'issuer_2', + 'user_identifier_claim' => 'id_2', + 'base64_headers' => ['x-istio-jwt-payload'], + ], ], ], ], @@ -84,13 +86,23 @@ function (ContainerBuilder $container) { 'provider' => 'memory', 'stateless' => true, 'istio_jwt_authenticator' => [ - [ - 'issuer' => 'issuer_2', - 'user_identifier_claim' => 'id_2', - 'origin_token_headers' => ['authorization'], + 'rules' => [ + [ + 'issuer' => 'issuer_2', + 'user_identifier_claim' => 'id_2', + 'origin_token_headers' => ['authorization'], + ], ], ], ], + // Test not affect another authenticator + 'test3' => [ + 'provider' => 'istio', + 'stateless' => true, + 'http_basic' => [ + 'realm' => 'Test', + ], + ], ], 'providers' => [ 'istio' => [ diff --git a/tests/Unit/DepdendencyInjection/Security/AuthenticatorFactoryTest.php b/tests/Unit/DepdendencyInjection/Security/AuthenticatorFactoryTest.php index ed7844d..511f4e5 100644 --- a/tests/Unit/DepdendencyInjection/Security/AuthenticatorFactoryTest.php +++ b/tests/Unit/DepdendencyInjection/Security/AuthenticatorFactoryTest.php @@ -67,8 +67,10 @@ public function testExceptionWhenCallCreate() public function testCreateAuthenticator() { $config = [ - ['issuer' => 'test', 'origin_token_headers' => ['authorization'], 'user_identifier_claim' => 'sub'], - ['issuer' => 'test2', 'origin_token_query_params' => ['token'], 'user_identifier_claim' => 'sub'], + 'rules' => [ + ['issuer' => 'test', 'origin_token_headers' => ['authorization'], 'user_identifier_claim' => 'sub'], + ['issuer' => 'test2', 'origin_token_query_params' => ['token'], 'user_identifier_claim' => 'sub'], + ], ]; $this->executeCreate($config); @@ -84,7 +86,7 @@ public function testCreateAuthenticator() public function testThrowExceptionWhenCreateAuthenticatorWithNoneExtractor() { $this->expectException(InvalidConfigurationException::class); - $this->executeCreate([['issuer' => 'test']]); + $this->executeCreate(['rules' => ['issuer' => 'test']]); } private function executeCreate(array $config) @@ -98,37 +100,69 @@ public function validConfigurations(): array return [ [ [ - [ - 'issuer' => 'example', + 'rules' => [ + [ + 'issuer' => 'example', + ], ], ], [ - [ - 'issuer' => 'example', - 'user_identifier_claim' => 'sub', - 'origin_token_headers' => [], - 'origin_token_query_params' => [], - 'base64_headers' => [], + 'rules' => [ + [ + 'issuer' => 'example', + 'user_identifier_claim' => 'sub', + 'origin_token_headers' => [], + 'origin_token_query_params' => [], + 'base64_headers' => [], + ], ], ], ], [ [ - [ - 'issuer' => 'example', - 'user_identifier_claim' => 'id', - 'origin_token_headers' => ['authorization'], - 'origin_token_query_params' => ['token'], - 'base64_headers' => ['x-istio-jwt-payload'], + 'rules' => [ + [ + 'issuer' => 'example', + 'user_identifier_claim' => 'id', + 'origin_token_headers' => ['authorization'], + 'origin_token_query_params' => ['token'], + 'base64_headers' => ['x-istio-jwt-payload'], + ], ], ], [ - [ - 'issuer' => 'example', - 'user_identifier_claim' => 'id', - 'origin_token_headers' => ['authorization'], - 'origin_token_query_params' => ['token'], - 'base64_headers' => ['x-istio-jwt-payload'], + 'rules' => [ + [ + 'issuer' => 'example', + 'user_identifier_claim' => 'id', + 'origin_token_headers' => ['authorization'], + 'origin_token_query_params' => ['token'], + 'base64_headers' => ['x-istio-jwt-payload'], + ], + ], + ], + ], + [ + [ + 'rules' => [ + [ + 'issuer' => 'example', + 'user_identifier_claim' => 'id', + 'origin_token_header' => ['authorization'], + 'origin_token_query_param' => ['token'], + 'base64_header' => ['x-istio-jwt-payload'], + ], + ], + ], + [ + 'rules' => [ + [ + 'issuer' => 'example', + 'user_identifier_claim' => 'id', + 'origin_token_headers' => ['authorization'], + 'origin_token_query_params' => ['token'], + 'base64_headers' => ['x-istio-jwt-payload'], + ], ], ], ], @@ -138,34 +172,64 @@ public function validConfigurations(): array public function invalidConfigurations(): array { return [ + [ + [], + ], [ [ - ['issuer' => ''], + 'rules' => [], ], ], [ [ - ['issuer' => 'example', 'user_identifier_claim' => ''], + 'rules' => [[]], ], ], [ [ - ['issuer' => '', 'user_identifier_claim' => 'id'], + 'rules' => ['issuer' => ''], ], ], [ [ - ['issuer' => 'example', 'origin_token_headers' => ['']], + 'rules' => [ + ['issuer' => ''], + ], ], ], [ [ - ['issuer' => 'example', 'origin_token_query_params' => ['']], + 'rules' => [ + ['issuer' => 'example', 'user_identifier_claim' => ''], + ], ], ], [ [ - ['issuer' => 'example', 'base64_headers' => ['']], + 'rules' => [ + ['issuer' => '', 'user_identifier_claim' => 'id'], + ], + ], + ], + [ + [ + 'rules' => [ + ['issuer' => 'example', 'origin_token_headers' => ['']], + ], + ], + ], + [ + [ + 'rules' => [ + ['issuer' => 'example', 'origin_token_query_params' => ['']], + ], + ], + ], + [ + [ + 'rules' => [ + ['issuer' => 'example', 'base64_headers' => ['']], + ], ], ], ];