1
+ <?php
2
+
3
+ namespace Symfony \Component \Security \Guard \Firewall ;
4
+
5
+ use Symfony \Component \HttpFoundation \Request ;
6
+ use Symfony \Component \HttpFoundation \Response ;
7
+ use Symfony \Component \HttpKernel \Event \GetResponseEvent ;
8
+ use Symfony \Component \Security \Guard \GuardAuthenticatorHandler ;
9
+ use Symfony \Component \Security \Guard \Token \NonAuthenticatedGuardToken ;
10
+ use Symfony \Component \Security \Core \Authentication \AuthenticationManagerInterface ;
11
+ use Symfony \Component \Security \Guard \GuardAuthenticatorInterface ;
12
+ use Psr \Log \LoggerInterface ;
13
+ use Symfony \Component \Security \Core \Authentication \Token \TokenInterface ;
14
+ use Symfony \Component \Security \Core \Exception \AuthenticationException ;
15
+ use Symfony \Component \Security \Http \Firewall \ListenerInterface ;
16
+ use Symfony \Component \Security \Http \RememberMe \RememberMeServicesInterface ;
17
+
18
+ /**
19
+ * Authentication listener for the "guard" system
20
+ *
21
+ * @author Ryan Weaver <[email protected] >
22
+ */
23
+ class GuardAuthenticationListener implements ListenerInterface
24
+ {
25
+ private $ guardHandler ;
26
+ private $ authenticationManager ;
27
+ private $ providerKey ;
28
+ private $ guardAuthenticators ;
29
+ private $ logger ;
30
+ private $ rememberMeServices ;
31
+
32
+ /**
33
+ * @param GuardAuthenticatorHandler $guardHandler The Guard handler
34
+ * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
35
+ * @param string $providerKey The provider (i.e. firewall) key
36
+ * @param GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
37
+ * @param LoggerInterface $logger A LoggerInterface instance
38
+ */
39
+ public function __construct (GuardAuthenticatorHandler $ guardHandler , AuthenticationManagerInterface $ authenticationManager , $ providerKey , $ guardAuthenticators , LoggerInterface $ logger = null )
40
+ {
41
+ if (empty ($ providerKey )) {
42
+ throw new \InvalidArgumentException ('$providerKey must not be empty. ' );
43
+ }
44
+
45
+ $ this ->guardHandler = $ guardHandler ;
46
+ $ this ->authenticationManager = $ authenticationManager ;
47
+ $ this ->providerKey = $ providerKey ;
48
+ $ this ->guardAuthenticators = $ guardAuthenticators ;
49
+ $ this ->logger = $ logger ;
50
+ }
51
+
52
+ /**
53
+ * Iterates over each authenticator to see if each wants to authenticate the request
54
+ *
55
+ * @param GetResponseEvent $event
56
+ */
57
+ public function handle (GetResponseEvent $ event )
58
+ {
59
+ if (null !== $ this ->logger ) {
60
+ $ this ->logger ->info ('Checking for guard authentication credentials ' , array ('firewall_key ' => $ this ->providerKey , 'authenticators ' => count ($ this ->guardAuthenticators )));
61
+ }
62
+
63
+ foreach ($ this ->guardAuthenticators as $ key => $ guardAuthenticator ) {
64
+ // get a key that's unique to *this* guard authenticator
65
+ // this MUST be the same as GuardAuthenticationProvider
66
+ $ uniqueGuardKey = $ this ->providerKey .'_ ' .$ key ;
67
+
68
+ $ this ->executeGuardAuthenticator ($ uniqueGuardKey , $ guardAuthenticator , $ event );
69
+ }
70
+ }
71
+
72
+ private function executeGuardAuthenticator ($ uniqueGuardKey , GuardAuthenticatorInterface $ guardAuthenticator , GetResponseEvent $ event )
73
+ {
74
+ $ request = $ event ->getRequest ();
75
+ try {
76
+ if (null !== $ this ->logger ) {
77
+ $ this ->logger ->info ('Calling getCredentialsFromRequest on guard configurator ' , array ('firewall_key ' => $ this ->providerKey , 'authenticator ' => get_class ($ guardAuthenticator )));
78
+ }
79
+
80
+ // allow the authenticator to fetch authentication info from the request
81
+ $ credentials = $ guardAuthenticator ->getCredentialsFromRequest ($ request );
82
+
83
+ // allow null to be returned to skip authentication
84
+ if (null === $ credentials ) {
85
+ return ;
86
+ }
87
+
88
+ // create a token with the unique key, so that the provider knows which authenticator to use
89
+ $ token = new NonAuthenticatedGuardToken ($ credentials , $ uniqueGuardKey );
90
+
91
+ if (null !== $ this ->logger ) {
92
+ $ this ->logger ->info ('Passing guard token information to the GuardAuthenticationProvider ' , array ('firewall_key ' => $ this ->providerKey , 'authenticator ' => get_class ($ guardAuthenticator )));
93
+ }
94
+ // pass the token into the AuthenticationManager system
95
+ // this indirectly calls GuardAuthenticationProvider::authenticate()
96
+ $ token = $ this ->authenticationManager ->authenticate ($ token );
97
+
98
+ if (null !== $ this ->logger ) {
99
+ $ this ->logger ->info ('Guard authentication successful! ' , array ('token ' => $ token , 'authenticator ' => get_class ($ guardAuthenticator )));
100
+ }
101
+
102
+ // sets the token on the token storage, etc
103
+ $ this ->guardHandler ->authenticateWithToken ($ token , $ request );
104
+ } catch (AuthenticationException $ e ) {
105
+ // oh no! Authentication failed!
106
+
107
+ if (null !== $ this ->logger ) {
108
+ $ this ->logger ->info ('Guard authentication failed. ' , array ('exception ' => $ e , 'authenticator ' => get_class ($ guardAuthenticator )));
109
+ }
110
+
111
+ $ response = $ this ->guardHandler ->handleAuthenticationFailure ($ e , $ request , $ guardAuthenticator );
112
+
113
+ if ($ response instanceof Response) {
114
+ $ event ->setResponse ($ response );
115
+ }
116
+
117
+ return ;
118
+ }
119
+
120
+ // success!
121
+ $ response = $ this ->guardHandler ->handleAuthenticationSuccess ($ token , $ request , $ guardAuthenticator , $ this ->providerKey );
122
+ if ($ response instanceof Response) {
123
+ if (null !== $ this ->logger ) {
124
+ $ this ->logger ->info ('Guard authenticator set success response ' , array ('response ' => $ response , 'authenticator ' => get_class ($ guardAuthenticator )));
125
+ }
126
+
127
+ $ event ->setResponse ($ response );
128
+ } else {
129
+ if (null !== $ this ->logger ) {
130
+ $ this ->logger ->info ('Guard authenticator set no success response: request continues ' , array ('authenticator ' => get_class ($ guardAuthenticator )));
131
+ }
132
+ }
133
+
134
+ // attempt to trigger the remember me functionality
135
+ $ this ->triggerRememberMe ($ guardAuthenticator , $ request , $ token , $ response );
136
+ }
137
+
138
+ /**
139
+ * Should be called if this listener will support remember me.
140
+ *
141
+ * @param RememberMeServicesInterface $rememberMeServices
142
+ */
143
+ public function setRememberMeServices (RememberMeServicesInterface $ rememberMeServices )
144
+ {
145
+ $ this ->rememberMeServices = $ rememberMeServices ;
146
+ }
147
+
148
+ /**
149
+ * Checks to see if remember me is supported in the authenticator and
150
+ * on the firewall. If it is, the RememberMeServicesInterface is notified
151
+ *
152
+ * @param GuardAuthenticatorInterface $guardAuthenticator
153
+ * @param Request $request
154
+ * @param TokenInterface $token
155
+ * @param Response $response
156
+ */
157
+ private function triggerRememberMe (GuardAuthenticatorInterface $ guardAuthenticator , Request $ request , TokenInterface $ token , Response $ response = null )
158
+ {
159
+ if (!$ guardAuthenticator ->supportsRememberMe ()) {
160
+ return ;
161
+ }
162
+
163
+ if (null === $ this ->rememberMeServices ) {
164
+ if (null !== $ this ->logger ) {
165
+ $ this ->logger ->info ('Remember me skipped: it is not configured for the firewall ' , array ('authenticator ' => get_class ($ guardAuthenticator )));
166
+ }
167
+
168
+ return ;
169
+ }
170
+
171
+ if (!$ response instanceof Response) {
172
+ throw new \LogicException (sprintf (
173
+ '%s::onAuthenticationSuccess *must* return a Response if you want to use the remember me functionality. Return a Response, or set remember_me to false under the guard configuration. ' ,
174
+ get_class ($ guardAuthenticator )
175
+ ));
176
+ }
177
+
178
+ $ this ->rememberMeServices ->loginSuccess ($ request , $ response , $ token );
179
+ }
180
+ }
0 commit comments