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); |
||
0 ignored issues
–
show
|
|||
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
The call to
Attempting::__construct() has too many arguments starting with $login .
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
Loading history...
|
|||
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); |
||
0 ignored issues
–
show
It seems like
$token defined by $this->getRequestToken() on line 301 can also be of type array ; however, WWON\JwtGuard\JwtService::invalidateToken() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
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); |
||
0 ignored issues
–
show
It seems like
$token defined by $this->getRequestToken() on line 321 can also be of type array ; however, WWON\JwtGuard\JwtService::getClaimFromToken() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
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); |
||
0 ignored issues
–
show
It seems like
$token defined by $this->getRequestToken() on line 361 can also be of type array ; however, WWON\JwtGuard\JwtGuard::refreshTokenForUser() does only seem to accept string , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.
Loading history...
|
|||
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) { |
||
0 ignored issues
–
show
The expression
$token of type string|null is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
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 | } |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.