11
11
12
12
namespace Symfony \Bundle \SecurityBundle \DependencyInjection \Security \Factory ;
13
13
14
+ use Symfony \Bundle \SecurityBundle \DependencyInjection \Security \AccessToken \TokenHandlerFactoryInterface ;
14
15
use Symfony \Component \Config \Definition \Builder \NodeDefinition ;
16
+ use Symfony \Component \Config \Definition \Exception \InvalidConfigurationException ;
15
17
use Symfony \Component \DependencyInjection \ChildDefinition ;
16
18
use Symfony \Component \DependencyInjection \ContainerBuilder ;
17
19
use Symfony \Component \DependencyInjection \Reference ;
20
22
* AccessTokenFactory creates services for Access Token authentication.
21
23
*
22
24
* @author Florent Morselli <florent.morselli@spomky-labs.com>
25
+ * @author Vincent Chalamon <vincentchalamon@gmail.com>
23
26
*
24
27
* @internal
25
28
*/
26
29
final class AccessTokenFactory extends AbstractFactory
27
30
{
28
31
private const PRIORITY = -40 ;
29
32
30
- public function __construct ()
33
+ /**
34
+ * @param array<array-key, TokenHandlerFactoryInterface> $tokenHandlerFactories
35
+ */
36
+ public function __construct (private readonly array $ tokenHandlerFactories )
31
37
{
32
38
$ this ->options = [];
33
39
$ this ->defaultFailureHandlerOptions = [];
@@ -39,7 +45,6 @@ public function addConfiguration(NodeDefinition $node): void
39
45
$ builder = $ node ->children ();
40
46
41
47
$ builder
42
- ->scalarNode ('token_handler ' )->isRequired ()->end ()
43
48
->scalarNode ('user_provider ' )->defaultNull ()->end ()
44
49
->scalarNode ('realm ' )->defaultNull ()->end ()
45
50
->scalarNode ('success_handler ' )->defaultNull ()->end ()
@@ -57,6 +62,38 @@ public function addConfiguration(NodeDefinition $node): void
57
62
->scalarPrototype ()->end ()
58
63
->end ()
59
64
;
65
+
66
+ $ tokenHandlerNodeBuilder = $ builder
67
+ ->arrayNode ('token_handler ' )
68
+ ->example ([
69
+ 'id ' => 'App\Security\CustomTokenHandler ' ,
70
+ ])
71
+
72
+ ->beforeNormalization ()
73
+ ->ifString ()
74
+ ->then (static function (string $ v ): array { return ['id ' => $ v ]; })
75
+ ->end ()
76
+
77
+ ->beforeNormalization ()
78
+ ->ifTrue (static function ($ v ) { return \is_array ($ v ) && 1 < \count ($ v ); })
79
+ ->then (static function () { throw new InvalidConfigurationException ('You cannot configure multiple token handlers. ' ); })
80
+ ->end ()
81
+
82
+ // "isRequired" must be set otherwise the following custom validation is not called
83
+ ->isRequired ()
84
+ ->beforeNormalization ()
85
+ ->ifTrue (static function ($ v ) { return \is_array ($ v ) && 1 > \count ($ v ); })
86
+ ->then (static function () { throw new InvalidConfigurationException ('You must set a token handler. ' ); })
87
+ ->end ()
88
+
89
+ ->children ()
90
+ ;
91
+
92
+ foreach ($ this ->tokenHandlerFactories as $ factory ) {
93
+ $ factory ->addConfiguration ($ tokenHandlerNodeBuilder );
94
+ }
95
+
96
+ $ tokenHandlerNodeBuilder ->end ();
60
97
}
61
98
62
99
public function getPriority (): int
@@ -76,10 +113,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
76
113
$ failureHandler = isset ($ config ['failure_handler ' ]) ? new Reference ($ this ->createAuthenticationFailureHandler ($ container , $ firewallName , $ config )) : null ;
77
114
$ authenticatorId = sprintf ('security.authenticator.access_token.%s ' , $ firewallName );
78
115
$ extractorId = $ this ->createExtractor ($ container , $ firewallName , $ config ['token_extractors ' ]);
116
+ $ tokenHandlerId = $ this ->createTokenHandler ($ container , $ firewallName , $ config ['token_handler ' ]);
79
117
80
118
$ container
81
119
->setDefinition ($ authenticatorId , new ChildDefinition ('security.authenticator.access_token ' ))
82
- ->replaceArgument (0 , new Reference ($ config [ ' token_handler ' ] ))
120
+ ->replaceArgument (0 , new Reference ($ tokenHandlerId ))
83
121
->replaceArgument (1 , new Reference ($ extractorId ))
84
122
->replaceArgument (2 , $ userProvider )
85
123
->replaceArgument (3 , $ successHandler )
@@ -115,4 +153,20 @@ private function createExtractor(ContainerBuilder $container, string $firewallNa
115
153
116
154
return $ extractorId ;
117
155
}
156
+
157
+ private function createTokenHandler (ContainerBuilder $ container , string $ firewallName , array $ config ): string
158
+ {
159
+ $ key = array_keys ($ config )[0 ];
160
+ $ id = sprintf ('security.access_token_handler.%s ' , $ firewallName );
161
+
162
+ foreach ($ this ->tokenHandlerFactories as $ factory ) {
163
+ if ($ key !== $ factory ->getKey ()) {
164
+ continue ;
165
+ }
166
+
167
+ $ factory ->create ($ container , $ id , $ config [$ key ]);
168
+ }
169
+
170
+ return $ id ;
171
+ }
118
172
}
0 commit comments