2020use Symfony \Component \HttpFoundation \Cookie ;
2121use Symfony \Component \Security \Http \EventListener \RememberMeLogoutListener ;
2222
23- class RememberMeFactory implements SecurityFactoryInterface
23+ class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2424{
2525 protected $ options = [
2626 'name ' => 'REMEMBERME ' ,
@@ -46,29 +46,8 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
4646 ;
4747
4848 // remember me services
49- if (isset ($ config ['service ' ])) {
50- $ templateId = $ config ['service ' ];
51- $ rememberMeServicesId = $ templateId .'. ' .$ id ;
52- } elseif (isset ($ config ['token_provider ' ])) {
53- $ templateId = 'security.authentication.rememberme.services.persistent ' ;
54- $ rememberMeServicesId = $ templateId .'. ' .$ id ;
55- } else {
56- $ templateId = 'security.authentication.rememberme.services.simplehash ' ;
57- $ rememberMeServicesId = $ templateId .'. ' .$ id ;
58- }
59-
60- $ rememberMeServices = $ container ->setDefinition ($ rememberMeServicesId , new ChildDefinition ($ templateId ));
61- $ rememberMeServices ->replaceArgument (1 , $ config ['secret ' ]);
62- $ rememberMeServices ->replaceArgument (2 , $ id );
63-
64- if (isset ($ config ['token_provider ' ])) {
65- $ rememberMeServices ->addMethodCall ('setTokenProvider ' , [
66- new Reference ($ config ['token_provider ' ]),
67- ]);
68- }
69-
70- // remember-me options
71- $ rememberMeServices ->replaceArgument (3 , array_intersect_key ($ config , $ this ->options ));
49+ $ templateId = $ this ->generateRememberMeServicesTemplateId ($ config , $ id );
50+ $ rememberMeServicesId = $ templateId .'. ' .$ id ;
7251
7352 // attach to remember-me aware listeners
7453 $ userProviders = [];
@@ -93,17 +72,8 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
9372 ;
9473 }
9574 }
96- if ($ config ['user_providers ' ]) {
97- $ userProviders = [];
98- foreach ($ config ['user_providers ' ] as $ providerName ) {
99- $ userProviders [] = new Reference ('security.user.provider.concrete. ' .$ providerName );
100- }
101- }
102- if (0 === \count ($ userProviders )) {
103- throw new \RuntimeException ('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled. ' );
104- }
10575
106- $ rememberMeServices -> replaceArgument ( 0 , new IteratorArgument ( array_unique ( $ userProviders)) );
76+ $ this -> createRememberMeServices ( $ container , $ id , $ templateId , $ userProviders, $ config );
10777
10878 // remember-me listener
10979 $ listenerId = 'security.authentication.listener.rememberme. ' .$ id ;
@@ -119,6 +89,42 @@ public function create(ContainerBuilder $container, string $id, array $config, ?
11989 return [$ authProviderId , $ listenerId , $ defaultEntryPoint ];
12090 }
12191
92+ public function createAuthenticator (ContainerBuilder $ container , string $ id , array $ config , string $ userProviderId ): string
93+ {
94+ $ templateId = $ this ->generateRememberMeServicesTemplateId ($ config , $ id );
95+ $ rememberMeServicesId = $ templateId .'. ' .$ id ;
96+
97+ // create remember me services (which manage the remember me cookies)
98+ $ this ->createRememberMeServices ($ container , $ id , $ templateId , [new Reference ($ userProviderId )], $ config );
99+
100+ // create remember me listener (which executes the remember me services for other authenticators and logout)
101+ $ this ->createRememberMeListener ($ container , $ id , $ rememberMeServicesId );
102+
103+ // create remember me authenticator (which re-authenticates the user based on the remember me cookie)
104+ $ authenticatorId = 'security.authenticator.remember_me. ' .$ id ;
105+ $ container
106+ ->setDefinition ($ authenticatorId , new ChildDefinition ('security.authenticator.remember_me ' ))
107+ ->replaceArgument (0 , new Reference ($ rememberMeServicesId ))
108+ ->replaceArgument (3 , array_intersect_key ($ config , $ this ->options ))
109+ ;
110+
111+ foreach ($ container ->findTaggedServiceIds ('security.remember_me_aware ' ) as $ serviceId => $ attributes ) {
112+ // register ContextListener
113+ if ('security.context_listener ' === substr ($ serviceId , 0 , 25 )) {
114+ $ container
115+ ->getDefinition ($ serviceId )
116+ ->addMethodCall ('setRememberMeServices ' , [new Reference ($ rememberMeServicesId )])
117+ ;
118+
119+ continue ;
120+ }
121+
122+ throw new \LogicException (sprintf ('Symfony Authenticator Security dropped support for the "security.remember_me_aware" tag, service "%s" will no longer work as expected. ' , $ serviceId ));
123+ }
124+
125+ return $ authenticatorId ;
126+ }
127+
122128 public function getPosition ()
123129 {
124130 return 'remember_me ' ;
@@ -163,4 +169,63 @@ public function addConfiguration(NodeDefinition $node)
163169 }
164170 }
165171 }
172+
173+ private function generateRememberMeServicesTemplateId (array $ config , string $ id ): string
174+ {
175+ if (isset ($ config ['service ' ])) {
176+ return $ config ['service ' ];
177+ }
178+
179+ if (isset ($ config ['token_provider ' ])) {
180+ return 'security.authentication.rememberme.services.persistent ' ;
181+ }
182+
183+ return 'security.authentication.rememberme.services.simplehash ' ;
184+ }
185+
186+ private function createRememberMeServices (ContainerBuilder $ container , string $ id , string $ templateId , array $ userProviders , array $ config ): void
187+ {
188+ $ rememberMeServicesId = $ templateId .'. ' .$ id ;
189+
190+ $ rememberMeServices = $ container ->setDefinition ($ rememberMeServicesId , new ChildDefinition ($ templateId ));
191+ $ rememberMeServices ->replaceArgument (1 , $ config ['secret ' ]);
192+ $ rememberMeServices ->replaceArgument (2 , $ id );
193+
194+ if (isset ($ config ['token_provider ' ])) {
195+ $ rememberMeServices ->addMethodCall ('setTokenProvider ' , [
196+ new Reference ($ config ['token_provider ' ]),
197+ ]);
198+ }
199+
200+ // remember-me options
201+ $ rememberMeServices ->replaceArgument (3 , array_intersect_key ($ config , $ this ->options ));
202+
203+ if ($ config ['user_providers ' ]) {
204+ $ userProviders = [];
205+ foreach ($ config ['user_providers ' ] as $ providerName ) {
206+ $ userProviders [] = new Reference ('security.user.provider.concrete. ' .$ providerName );
207+ }
208+ }
209+
210+ if (0 === \count ($ userProviders )) {
211+ throw new \RuntimeException ('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled. ' );
212+ }
213+
214+ $ rememberMeServices ->replaceArgument (0 , new IteratorArgument (array_unique ($ userProviders )));
215+ }
216+
217+ private function createRememberMeListener (ContainerBuilder $ container , string $ id , string $ rememberMeServicesId ): void
218+ {
219+ $ container
220+ ->setDefinition ('security.listener.remember_me. ' .$ id , new ChildDefinition ('security.listener.remember_me ' ))
221+ ->addTag ('kernel.event_subscriber ' )
222+ ->replaceArgument (0 , new Reference ($ rememberMeServicesId ))
223+ ->replaceArgument (1 , $ id )
224+ ;
225+
226+ $ container
227+ ->setDefinition ('security.logout.listener.remember_me. ' .$ id , new Definition (RememberMeLogoutListener::class))
228+ ->addTag ('kernel.event_subscriber ' , ['dispatcher ' => 'security.event_dispatcher. ' .$ id ])
229+ ->addArgument (new Reference ($ rememberMeServicesId ));
230+ }
166231}
0 commit comments