JWTAuth::fromUser()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4286
cc 1
eloc 5
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Tymon\JWTAuth;
4
5
use Illuminate\Http\Request;
6
use Tymon\JWTAuth\Exceptions\InvalidClaimException;
7
use Tymon\JWTAuth\Exceptions\JWTException;
8
use Tymon\JWTAuth\Providers\Auth\AuthInterface;
9
use Tymon\JWTAuth\Providers\User\UserInterface;
10
use \Illuminate\Contracts\Auth\Authenticatable;
11
12
class JWTAuth
13
{
14
    /**
15
     * @var \Tymon\JWTAuth\JWTManager
16
     */
17
    protected $manager;
18
19
    /**
20
     * @var \Tymon\JWTAuth\Providers\User\UserInterface
21
     */
22
    protected $user;
23
24
    /**
25
     * @var \Tymon\JWTAuth\Providers\Auth\AuthInterface
26
     */
27
    protected $auth;
28
29
    /**
30
     * @var \Illuminate\Http\Request
31
     */
32
    protected $request;
33
34
    /**
35
     * @var string
36
     */
37
    protected $identifier = 'id';
38
39
    /**
40
     * @var \Tymon\JWTAuth\Token
41
     */
42
    protected $token;
43
44
45
    /**
46
     * @var \Illuminate\Contracts\Auth\Authenticatable
47
     */
48
    protected $userModel = null;
49
50
    /**
51
     * @param \Tymon\JWTAuth\JWTManager                   $manager
52
     * @param \Tymon\JWTAuth\Providers\User\UserInterface $user
53
     * @param \Tymon\JWTAuth\Providers\Auth\AuthInterface $auth
54
     * @param \Illuminate\Http\Request                    $request
55
     */
56 54
    public function __construct(JWTManager $manager, UserInterface $user, AuthInterface $auth, Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
57
    {
58 54
        $this->manager = $manager;
59 54
        $this->user = $user;
60 54
        $this->auth = $auth;
61 54
        $this->request = $request;
62 54
    }
63
64
    /**
65
     * @return \Illuminate\Contracts\Auth\Authenticatable
66
     */
67
    public function getUserModel()
68
    {
69
        return $this->userModel;
70
    }
71
72
    /**
73
     * @param \Illuminate\Contracts\Auth\Authenticatable $userModel
74
     */
75
    public function setUserModel(Authenticatable $userModel)
76
    {
77
        $this->userModel = $userModel;
78
    }
79
80
    /**
81
     * @param $userModel
82
     */
83 12
    private function setUserModelAsObject ($userModel)
84
    {
85 12
        $this->userModel = $userModel;
86 12
    }
87
88
89
90
    /**
91
     * Find a user using the user identifier in the subject claim.
92
     *
93
     * @param bool|string $token
94
     *
95
     * @return mixed
96
     */
97 9
    public function toUser($token = false)
98
    {
99 9
        $payload = $this->getPayload($token);
100
101 6
        if (! $user = $this->user->getBy($this->identifier, $payload['sub'])) {
102 3
            return false;
103
        }
104
105 3
        $this->setUserModelAsObject($user);
106 3
        return $user;
107
    }
108
109
    /**
110
     * Generate a token using the user identifier as the subject claim.
111
     *
112
     * @param mixed $user
113
     * @param array $customClaims
114
     *
115
     * @return string
116
     */
117 6
    public function fromUser($user, array $customClaims = [])
118
    {
119 6
        $payload = $this->makePayload($user->{$this->identifier}, $customClaims);
120
121 6
        $ret = $this->manager->encode($payload)->get();
122 6
        $this->setUserModelAsObject($user);
123 6
        return $ret;
124
    }
125
126
    /**
127
     * Attempt to authenticate the user and return the token.
128
     *
129
     * @param array $credentials
130
     * @param array $customClaims
131
     *
132
     * @return false|string
133
     * @throws JWTException
134
     */
135 6
    public function attempt(array $credentials = [], array $customClaims = [])
136
    {
137 6
        if (! $this->auth->byCredentials($credentials)) {
138 3
            return false;
139
        }
140
141 3
        return $this->fromUser($this->auth->user(), $customClaims);
142
    }
143
144
    /**
145
     * Authenticate a user via a token.
146
     *
147
     * @param mixed $token
148
     * @param Array $custom custom claims that must be equals (all custom fields indicated must be equals in token, this doesn't entail that the token must have only these claims)
149
     * @return mixed
150
     */
151 6
    public function authenticate($token = false, $custom = [])
152
    {
153 6
        $payload = $this->getPayload($token);
154 6
        $id = $payload->get('sub');
155
156 6
        foreach($custom as $customK => $customV)
157
            if(!isset($payload[$customK]) || $customV != $payload[$customK])
158
                return new InvalidClaimException('custom fields are wrong');
159
160
161 6
        if (! $this->auth->byId($id)) {
162 3
            return false;
163
        }
164
165 3
        $user = $this->auth->user();
166 3
        $this->setUserModelAsObject($user);
167 3
        return $user;
168
    }
169
170
    /**
171
     * Refresh an expired token.
172
     *
173
     * @param mixed $token
174
     * @param Array $custom
175
     *
176
     * @return string
177
     */
178 3
    public function refresh($token = false, $custom = [])
179
    {
180 3
        $this->requireToken($token);
181
182 3
        return $this->manager->refresh($this->token, $custom)->get();
183
    }
184
185
    /**
186
     * Invalidate a token (add it to the blacklist).
187
     *
188
     * @param mixed $token
189
     *
190
     * @return boolean
191
     */
192 3
    public function invalidate($token = false)
193
    {
194 3
        $this->requireToken($token);
195
196 3
        return $this->manager->invalidate($this->token);
197
    }
198
199
    /**
200
     * Get the token.
201
     *
202
     * @return boolean|string
203
     */
204 12
    public function getToken()
205
    {
206 12
        if (! $this->token) {
207
            try {
208 6
                $this->parseToken();
209 5
            } catch (JWTException $e) {
210 3
                return false;
211
            }
212 2
        }
213
214 9
        return $this->token;
215
    }
216
217
    /**
218
     * Get the raw Payload instance.
219
     *
220
     * @param mixed $token
221
     *
222
     * @return \Tymon\JWTAuth\Payload
223
     */
224 15
    public function getPayload($token = false)
225
    {
226 15
        $this->requireToken($token);
227
228 12
        return $this->manager->decode($this->token);
229
    }
230
231
    /**
232
     * Parse the token from the request.
233
     * @param string $method
234
     * @param string $header
235
     * @param string $query
236
     * @return JWTAuth
237
     * @throws JWTException
238
     */
239 15
    public function parseToken($method = 'bearer', $header = 'authorization', $query = 'token')
240
    {
241 15
        if (! $token = $this->parseAuthHeader($header, $method)) {
242 12
            if (! $token = $this->request->query($query, false)) {
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
243 6
                throw new JWTException('The token could not be parsed from the request', 400);
244
            }
245 4
        }
246
247 9
        return $this->setToken($token);
0 ignored issues
show
Bug introduced by
It seems like $token can also be of type array; however, Tymon\JWTAuth\JWTAuth::setToken() 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...
248
    }
249
250
    /**
251
     * Parse token from the authorization header.
252
     *
253
     * @param string $header
254
     * @param string $method
255
     *
256
     * @return false|string
257
     */
258 15
    protected function parseAuthHeader($header = 'authorization', $method = 'bearer')
259
    {
260 15
        $header = $this->request->headers->get($header);
261
262 15
        if (! starts_with(strtolower($header), $method)) {
263 12
            return false;
264
        }
265
266 3
        return trim(str_ireplace($method, '', $header));
267
    }
268
269
    /**
270
     * Create a Payload instance.
271
     *
272
     * @param mixed $subject
273
     * @param array $customClaims
274
     *
275
     * @return \Tymon\JWTAuth\Payload
276
     */
277 6
    protected function makePayload($subject, array $customClaims = [])
278
    {
279 6
        return $this->manager->getPayloadFactory()->make(
280 6
            array_merge($customClaims, ['sub' => $subject])
281 4
        );
282
    }
283
284
    /**
285
     * Set the identifier.
286
     *
287
     * @param string $identifier
288
     *
289
     * @return $this
290
     */
291 3
    public function setIdentifier($identifier)
292
    {
293 3
        $this->identifier = $identifier;
294
295 3
        return $this;
296
    }
297
298
    /**
299
     * Get the identifier.
300
     *
301
     * @return string
302
     */
303 3
    public function getIdentifier()
304
    {
305 3
        return $this->identifier;
306
    }
307
308
    /**
309
     * Set the token.
310
     *
311
     * @param string $token
312
     *
313
     * @return $this
314
     */
315 27
    public function setToken($token)
316
    {
317 27
        $this->token = new Token($token);
318
319 27
        return $this;
320
    }
321
322
    /**
323
     * Ensure that a token is available.
324
     *
325
     * @param mixed $token
326
     *
327
     * @return JWTAuth
328
     *
329
     * @throws \Tymon\JWTAuth\Exceptions\JWTException
330
     */
331 21
    protected function requireToken($token)
332
    {
333 21
        if (! $token = $token ?: $this->token) {
334 3
            throw new JWTException('A token is required', 400);
335
        }
336
337 18
        return $this->setToken($token);
338
    }
339
340
    /**
341
     * Set the request instance.
342
     *
343
     * @param Request $request
344
     * @return $this
345
     */
346 3
    public function setRequest(Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
347
    {
348 3
        $this->request = $request;
349
350 3
        return $this;
351
    }
352
353
    /**
354
     * Get the JWTManager instance.
355
     *
356
     * @return \Tymon\JWTAuth\JWTManager
357
     */
358 3
    public function manager()
359
    {
360 3
        return $this->manager;
361
    }
362
363
    /**
364
     * Magically call the JWT Manager.
365
     *
366
     * @param string $method
367
     * @param array  $parameters
368
     *
369
     * @return mixed
370
     *
371
     * @throws \BadMethodCallException
372
     */
373 3
    public function __call($method, $parameters)
374
    {
375 3
        if (method_exists($this->manager, $method)) {
376 3
            return call_user_func_array([$this->manager, $method], $parameters);
377
        }
378
379
        throw new \BadMethodCallException("Method [$method] does not exist.");
380
    }
381
}
382