This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace WWON\JwtGuard; |
||
4 | |||
5 | use Illuminate\Auth\Events\Attempting; |
||
6 | use Illuminate\Auth\Events\Login; |
||
7 | use Illuminate\Auth\Events\Logout; |
||
8 | use Illuminate\Auth\GuardHelpers; |
||
9 | use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; |
||
10 | use Illuminate\Contracts\Auth\Guard; |
||
11 | use Illuminate\Contracts\Auth\UserProvider; |
||
12 | use Illuminate\Contracts\Events\Dispatcher; |
||
13 | use Illuminate\Http\Request; |
||
14 | use Illuminate\Support\Facades\Config; |
||
15 | use WWON\JwtGuard\Exceptions\Exception; |
||
16 | use WWON\JwtGuard\Exceptions\InaccessibleException; |
||
17 | use WWON\JwtGuard\Exceptions\InvalidTokenException; |
||
18 | use WWON\JwtGuard\Exceptions\MalformedException; |
||
19 | use WWON\JwtGuard\Exceptions\TokenExpiredException; |
||
20 | |||
21 | class JwtGuard implements Guard |
||
22 | { |
||
23 | |||
24 | use GuardHelpers; |
||
25 | |||
26 | /** |
||
27 | * @var string |
||
28 | */ |
||
29 | protected $token; |
||
30 | |||
31 | /** |
||
32 | * @var bool |
||
33 | */ |
||
34 | protected $isTokenRefreshable = false; |
||
35 | |||
36 | /** |
||
37 | * @var bool |
||
38 | */ |
||
39 | protected $isTokenPresent = false; |
||
40 | |||
41 | /** |
||
42 | * @var JwtService |
||
43 | */ |
||
44 | protected $jwtService; |
||
45 | |||
46 | /** |
||
47 | * @var Request |
||
48 | */ |
||
49 | protected $request; |
||
50 | |||
51 | /** |
||
52 | * The event dispatcher instance. |
||
53 | * |
||
54 | * @var Dispatcher |
||
55 | */ |
||
56 | protected $events; |
||
57 | |||
58 | /** |
||
59 | * Indicates if the logout method has been called. |
||
60 | * |
||
61 | * @var bool |
||
62 | */ |
||
63 | protected $loggedOut = false; |
||
64 | |||
65 | /** |
||
66 | * JwtGuard constructor |
||
67 | * |
||
68 | * @param UserProvider $provider |
||
69 | * @param JwtService $jwtService |
||
70 | * @param Request|null $request |
||
71 | */ |
||
72 | public function __construct( |
||
73 | UserProvider $provider, |
||
74 | JwtService $jwtService, |
||
75 | Request $request = null |
||
76 | ) { |
||
77 | $this->provider = $provider; |
||
78 | $this->jwtService = $jwtService; |
||
79 | $this->request = $request; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Get the currently authenticated user. |
||
84 | * |
||
85 | * @return \Illuminate\Contracts\Auth\Authenticatable|null |
||
86 | */ |
||
87 | public function user() |
||
88 | { |
||
89 | // If we've already retrieved the user for the current request we can just |
||
90 | // return it back immediately. We do not want to fetch the user data on |
||
91 | // every call to this method because that would be tremendously slow. |
||
92 | if ($this->user) { |
||
93 | return $this->user; |
||
94 | } |
||
95 | |||
96 | if (!$token = $this->getRequestToken()) { |
||
97 | return $this->user = null; |
||
98 | } |
||
99 | |||
100 | $this->isTokenPresent = true; |
||
101 | |||
102 | try { |
||
103 | $this->user = $this->getUserByToken($token); |
||
104 | } catch (InaccessibleException $e) { |
||
105 | $this->isTokenRefreshable = true; |
||
106 | $this->user = null; |
||
107 | } catch (Exception $e) { |
||
108 | $this->user = null; |
||
109 | } |
||
110 | |||
111 | return $this->user; |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Retrieve the user by the given payload. |
||
116 | * |
||
117 | * @param string $token |
||
118 | * @return AuthenticatableContract|null |
||
119 | * @throws InaccessibleException |
||
120 | * @throws MalformedException |
||
121 | * @throws TokenExpiredException |
||
122 | * @throws InvalidTokenException |
||
123 | */ |
||
124 | protected function getUserByToken($token) |
||
125 | { |
||
126 | $claim = $this->jwtService->getClaimFromToken($token); |
||
127 | $user = $this->provider->retrieveById($claim->sub); |
||
128 | |||
129 | if (!empty($user) && get_class($user) !== $claim->aud) { |
||
130 | throw new InvalidTokenException; |
||
131 | } |
||
132 | |||
133 | return $user; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Validate a user's credentials. |
||
138 | * |
||
139 | * @param array $credentials |
||
140 | * @return bool |
||
141 | */ |
||
142 | public function validate(array $credentials = []) |
||
143 | { |
||
144 | return $this->attempt($credentials, false); |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * Attempt to authenticate a user using the given credentials. |
||
149 | * |
||
150 | * @param array $credentials |
||
151 | * @param bool $login |
||
152 | * @return bool |
||
153 | */ |
||
154 | public function attempt(array $credentials = [], $login = true) |
||
155 | { |
||
156 | $this->fireAttemptEvent($credentials, $login); |
||
157 | |||
158 | $user = $this->provider->retrieveByCredentials($credentials); |
||
159 | |||
160 | if (empty($user)) { |
||
161 | return false; |
||
162 | } |
||
163 | |||
164 | // If an implementation of UserInterface was returned, we'll ask the provider |
||
165 | // to validate the user against the given credentials, and if they are in |
||
166 | // fact valid we'll log the users into the application and return true. |
||
167 | if ($this->hasValidCredentials($user, $credentials)) { |
||
168 | if ($login) { |
||
169 | $this->login($user); |
||
170 | } |
||
171 | |||
172 | return true; |
||
173 | } |
||
174 | |||
175 | return false; |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Determine if the user matches the credentials. |
||
180 | * |
||
181 | * @param mixed $user |
||
182 | * @param array $credentials |
||
183 | * @return bool |
||
184 | */ |
||
185 | protected function hasValidCredentials($user, $credentials) |
||
186 | { |
||
187 | return ! is_null($user) && $this->provider->validateCredentials($user, $credentials); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Fire the attempt event with the arguments. |
||
192 | * |
||
193 | * @param array $credentials |
||
194 | * @param bool $login |
||
195 | * @return void |
||
196 | */ |
||
197 | protected function fireAttemptEvent(array $credentials, $login) |
||
198 | { |
||
199 | if (isset($this->events)) { |
||
200 | $this->events->fire(new Attempting( |
||
201 | $credentials, false, $login |
||
0 ignored issues
–
show
|
|||
202 | )); |
||
203 | } |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Register an authentication attempt event listener. |
||
208 | * |
||
209 | * @param mixed $callback |
||
210 | * @return void |
||
211 | */ |
||
212 | public function attempting($callback) |
||
213 | { |
||
214 | if (isset($this->events)) { |
||
215 | $this->events->listen(Attempting::class, $callback); |
||
216 | } |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Log a user into the application. |
||
221 | * |
||
222 | * @param \Illuminate\Contracts\Auth\Authenticatable $user |
||
223 | * @return void |
||
224 | */ |
||
225 | public function login(AuthenticatableContract $user) |
||
226 | { |
||
227 | $claim = new Claim([ |
||
228 | 'sub' => $user->getAuthIdentifier(), |
||
229 | 'aud' => get_class($user), |
||
230 | 'refresh' => Config::get('jwt.refreshable') |
||
231 | ]); |
||
232 | |||
233 | $token = $this->jwtService->getTokenForClaim($claim); |
||
234 | |||
235 | // If we have an event dispatcher instance set we will fire an event so that |
||
236 | // any listeners will hook into the authentication events and run actions |
||
237 | // based on the login and logout events fired from the guard instances. |
||
238 | $this->fireLoginEvent($user); |
||
239 | |||
240 | $this->setToken($token); |
||
241 | $this->setUser($user); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * generateTokenForUser method |
||
246 | * |
||
247 | * @param string $token |
||
248 | * @return string |
||
249 | */ |
||
250 | protected function refreshTokenForUser($token) |
||
251 | { |
||
252 | try { |
||
253 | $newToken = $this->jwtService->refreshToken($token); |
||
254 | } catch (Exception $e) { |
||
255 | $newToken = null; |
||
256 | } |
||
257 | |||
258 | return $newToken; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Fire the login event if the dispatcher is set. |
||
263 | * |
||
264 | * @param \Illuminate\Contracts\Auth\Authenticatable $user |
||
265 | * @param bool $remember |
||
266 | * @return void |
||
267 | */ |
||
268 | protected function fireLoginEvent($user, $remember = false) |
||
269 | { |
||
270 | if (isset($this->events)) { |
||
271 | $this->events->fire(new Login($user, $remember)); |
||
272 | } |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * Log the given user ID into the application. |
||
277 | * |
||
278 | * @param mixed $id |
||
279 | * @return \Illuminate\Contracts\Auth\Authenticatable |
||
280 | */ |
||
281 | public function loginUsingId($id) |
||
282 | { |
||
283 | $user = $this->provider->retrieveById($id); |
||
284 | |||
285 | if (empty($user)) { |
||
286 | return null; |
||
287 | } |
||
288 | |||
289 | $this->login($user); |
||
290 | |||
291 | return $user; |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Log the user out of the application. |
||
296 | * |
||
297 | * @return void |
||
298 | */ |
||
299 | public function logout() |
||
300 | { |
||
301 | if (!$token = $this->getRequestToken()) { |
||
302 | return; |
||
303 | } |
||
304 | |||
305 | try { |
||
306 | $this->jwtService->invalidateToken($token); |
||
307 | } catch (Exception $e) { |
||
308 | // User has no valid token but fine with logout calling |
||
309 | } |
||
310 | |||
311 | $this->logoutCurrentUser(); |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * log this user out from every token |
||
316 | * |
||
317 | * @return void |
||
318 | */ |
||
319 | public function logoutAll() |
||
320 | { |
||
321 | if (!$token = $this->getRequestToken()) { |
||
322 | return; |
||
323 | } |
||
324 | |||
325 | try { |
||
326 | $claim = $this->jwtService->getClaimFromToken($token); |
||
327 | |||
328 | $this->jwtService->wipeUserTokens($claim); |
||
329 | |||
330 | } catch (Exception $e) { |
||
331 | // User has no valid token but fine with logout calling |
||
332 | } |
||
333 | |||
334 | $this->logoutCurrentUser(); |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * logoutCurrentUser method |
||
339 | */ |
||
340 | protected function logoutCurrentUser() |
||
341 | { |
||
342 | if (isset($this->events)) { |
||
343 | $this->events->fire(new Logout($this->user)); |
||
344 | } |
||
345 | |||
346 | // Once we have fired the logout event we will clear the users out of memory |
||
347 | // so they are no longer available as the user is no longer considered as |
||
348 | // being signed into this application and should not be available here. |
||
349 | $this->user = null; |
||
350 | $this->token = null; |
||
351 | $this->loggedOut = true; |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * Refresh user token |
||
356 | * |
||
357 | * @return string|null |
||
358 | */ |
||
359 | public function refreshToken() |
||
360 | { |
||
361 | if (!$token = $this->getRequestToken()) { |
||
362 | return null; |
||
363 | } |
||
364 | |||
365 | $this->token = $this->refreshTokenForUser($token); |
||
366 | |||
367 | return $this->token; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * Get the event dispatcher instance. |
||
372 | * |
||
373 | * @return Dispatcher |
||
374 | */ |
||
375 | public function getDispatcher() |
||
376 | { |
||
377 | return $this->events; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Set the event dispatcher instance. |
||
382 | * |
||
383 | * @param Dispatcher $events |
||
384 | * @return void |
||
385 | */ |
||
386 | public function setDispatcher(Dispatcher $events) |
||
387 | { |
||
388 | $this->events = $events; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * setToken method |
||
393 | * |
||
394 | * @param string $token |
||
395 | */ |
||
396 | public function setToken($token) |
||
397 | { |
||
398 | $this->token = $token; |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * getToken method |
||
403 | * |
||
404 | * @return null|string |
||
405 | */ |
||
406 | public function getToken() |
||
407 | { |
||
408 | return $this->token; |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * isTokenRefreshable method |
||
413 | * |
||
414 | * @return boolean |
||
415 | */ |
||
416 | public function isTokenRefreshable() |
||
417 | { |
||
418 | return $this->isTokenRefreshable; |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * isTokenPresent method |
||
423 | * |
||
424 | * @return boolean |
||
425 | */ |
||
426 | public function isTokenPresent() |
||
427 | { |
||
428 | return $this->isTokenPresent; |
||
429 | } |
||
430 | |||
431 | |||
432 | /** |
||
433 | * getRequestToken method |
||
434 | * |
||
435 | * @return string|null |
||
436 | */ |
||
437 | protected function getRequestToken() |
||
438 | { |
||
439 | $token = $this->getBearerToken(); |
||
440 | if (!$token) { |
||
441 | return $this->getCookieToken(); |
||
442 | } |
||
443 | |||
444 | return $token; |
||
445 | } |
||
446 | |||
447 | /** |
||
448 | * getBearerToken method |
||
449 | * |
||
450 | * @return string|null |
||
451 | */ |
||
452 | protected function getBearerToken() |
||
453 | { |
||
454 | $header = $this->request->header('Authorization', ''); |
||
455 | |||
456 | if (starts_with(strtolower($header), 'bearer ')) { |
||
457 | return mb_substr($header, 7, null, 'UTF-8'); |
||
458 | } |
||
459 | |||
460 | return null; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * getCookieToken method |
||
465 | * |
||
466 | * @return string|null |
||
467 | */ |
||
468 | protected function getCookieToken() |
||
469 | { |
||
470 | return $this->request->cookie('token'); |
||
471 | } |
||
472 | |||
473 | } |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.