JwtAuthenticator::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
/**
4
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
5
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE.txt
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
12
 * @link          https://cakephp.org CakePHP(tm) Project
13
 * @since         1.0.0
14
 * @license       https://opensource.org/licenses/mit-license.php MIT License
15
 */
16
17
namespace Phauthentic\Authentication\Authenticator;
18
19
use ArrayObject;
20
use Phauthentic\Authentication\Identifier\IdentifierInterface;
21
use Exception;
22
use Firebase\JWT\JWT;
23
use Firebase\JWT\Key;
24
use Psr\Http\Message\ServerRequestInterface;
25
use stdClass;
26
27
/**
28
 * Jwt Authenticator
29
 */
30
class JwtAuthenticator extends TokenAuthenticator
31
{
32
    /**
33
     * Query param
34
     *
35
     * @var null|string
36
     */
37
    protected ?string $queryParam = 'token';
38
39
    /**
40
     * Header
41
     *
42
     * @var null|string
43
     */
44
    protected ?string $header = 'Authorization';
45
46
    /**
47
     * Token Prefix
48
     *
49
     * @var null|string
50
     */
51
    protected ?string $tokenPrefix = 'bearer';
52
53
    /**
54
     * Hashing algorithms
55
     *
56
     * @var array<int, string>
57
     */
58
    protected array $algorithms = [
59
        'HS256'
60
    ];
61
62
    /**
63
     * Return payload
64
     *
65
     * @var bool
66
     */
67
    protected bool $returnPayload = true;
68
69
    /**
70
     * Secret key
71
     *
72
     * @var null|string
73
     */
74
    protected ?string $secretKey;
75
76
    /**
77
     * Payload data.
78
     *
79
     * @var object|null
80
     */
81
    protected ?object $payload = null;
82
83
    /**
84 28
     * {@inheritDoc}
85
     */
86 28
    public function __construct(IdentifierInterface $identifier, string $secretKey)
87
    {
88 28
        parent::__construct($identifier);
89 28
90
        $this->secretKey = $secretKey;
91
    }
92
93
    /**
94
     * Sets algorithms to use
95
     *
96
     * @param array<int, string> $algorithms List of algorithms
97
     * @return $this
98
     */
99
    public function setAlgorithms(array $algorithms): self
100
    {
101
        $this->algorithms = $algorithms;
102
103
        return $this;
104
    }
105
106
    /**
107
     * Sets return payload.
108
     *
109
     * @param bool $return Return payload.
110 4
     * @return $this
111
     */
112 4
    public function setReturnPayload(bool $return): self
113
    {
114 4
        $this->returnPayload = $return;
115
116
        return $this;
117
    }
118
119
    /**
120
     * Sets secret key.
121
     *
122
     * @param string $key Secret key.
123
     * @return $this
124
     */
125
    public function setSecretKey(string $key): self
126
    {
127
        $this->secretKey = $key;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Authenticates the identity based on a JWT token contained in a request.
134
     *
135
     * @link https://jwt.io/
136
     * @param \Psr\Http\Message\ServerRequestInterface $request The request that contains login information.
137 28
     * @return \Phauthentic\Authentication\Authenticator\ResultInterface
138
     */
139
    public function authenticate(ServerRequestInterface $request): ResultInterface
140 28
    {
141 4
        try {
142 4
            $result = $this->getPayload($request);
143 4
        } catch (Exception $e) {
144 4
            return new Result(
145
                null,
146 4
                Result::FAILURE_CREDENTIALS_INVALID,
147 4
                [
148
                    'message' => $e->getMessage(),
149
                    'exception' => $e
150
                ]
151
            );
152 24
        }
153 4
154
        if (!($result instanceof stdClass)) {
155
            return new Result(null, Result::FAILURE_CREDENTIALS_INVALID);
156 20
        }
157
158 20
        $result = json_decode((string)json_encode($result), true);
159 20
160 4
        $key = IdentifierInterface::CREDENTIAL_JWT_SUBJECT;
161
        if (empty($result[$key])) {
162
            return new Result(null, Result::FAILURE_CREDENTIALS_MISSING);
163 16
        }
164 12
165
        if ($this->returnPayload) {
166 12
            $user = new ArrayObject($result);
167
168
            return new Result($user, Result::SUCCESS);
169 4
        }
170 4
171
        $user = $this->identifier->identify([
172
            $key => $result[$key]
173 4
        ]);
174
175
        if (empty($user)) {
176
            return new Result(null, Result::FAILURE_IDENTITY_NOT_FOUND, $this->identifier->getErrors());
177 4
        }
178
179
        return new Result($user, Result::SUCCESS);
180
    }
181
182
    /**
183
     * Get payload data.
184
     *
185
     * @param \Psr\Http\Message\ServerRequestInterface|null $request Request to get authentication information from.
186 20
     * @return object|null Payload object on success, null on failure
187
     */
188 20
    public function getPayload(ServerRequestInterface $request = null)
189 4
    {
190
        if (!$request) {
191
            return $this->payload;
192 20
        }
193 20
194
        $payload = null;
195 20
        $token = $this->getToken($request);
196 20
197
        if ($token !== null) {
198
            $payload = $this->decodeToken($token);
199 16
        }
200
201 16
        $this->payload = $payload;
202
203
        return $this->payload;
204
    }
205
206
    /**
207
     * Decode JWT token.
208
     *
209
     * @param string $token JWT token to decode.
210 20
     * @return object|null The JWT's payload as a PHP object, null on failure.
211
     */
212 20
    protected function decodeToken($token)
213 20
    {
214 20
        return JWT::decode(
215 20
            $token,
216
            new Key((string)$this->secretKey, $this->algorithms[0])
217
        );
218
    }
219
}
220