jwtValidate::header()   A
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
1
<?php
2
3
/**
4
 * ==================================
5
 * Responsible PHP API
6
 * ==================================
7
 *
8
 * @link Git https://github.com/vince-scarpa/responsibleAPI.git
9
 *
10
 * @api Responible API
11
 * @package responsible\core\oauth
12
 *
13
 * @author Vince scarpa <[email protected]>
14
 *
15
 */
16
17
namespace responsible\core\auth;
18
19
use responsible\core\server;
20
use responsible\core\encoder;
21
use responsible\core\exception;
22
use responsible\core\route;
23
use responsible\core\user;
24
25
class jwtValidate extends jwt
26
{
27
    /**
28
     * [$TIMESTAMP]
29
     * @var int
30
     */
31
    protected static $TIMESTAMP;
32
33
    /**
34
     * [$LEEWAY]
35
     * @var int
36
     */
37
    protected static $LEEWAY = 0;
38
39
    /**
40
     * [$ALGORITHM]
41
     * @var string
42
     */
43
    private static $ALGORITHM;
0 ignored issues
show
introduced by
The private property $ALGORITHM is not used, and could be removed.
Loading history...
44
45
    /**
46
     * [$isPayloadValid Validation placeholders]
47
     * @var array
48
     */
49
    protected static $isPayloadValid = [
50
        "iss" => false,
51
        "sub" => false,
52
        "iat" => false,
53
        "nbf" => false,
54
        "exp" => false,
55
    ];
56
57
    /**
58
     * [unauthorised Set unauthorized headers]
59
     * @throws \responsible\core\exception\responsibleException
60
     * @return void
61
     */
62
    private static function unauthorised()
63
    {
64
        (new jwt())->setUnauthorised();
65
        // @codeCoverageIgnoreStart
66
    }
67
    // @codeCoverageIgnoreEnd
68
69
    /**
70
     * [header Validate the header object]
71
     * First segment of the token
72
     * @return void
73
     * @throws \responsible\core\exception\responsibleException
74
     */
75
    public static function header(array $headObject = [])
76
    {
77
        if (
78
            empty($headObject) ||
79
            !self::typ($headObject) ||
80
            !self::alg($headObject)
81
        ) {
82
            self::unauthorised();
83
        }
84
    }
85
86
    /**
87
     * [payload Validate the payload object]
88
     * Second segment of the token
89
     * @return bool
90
     * @throws \responsible\core\exception\responsibleException
91
     */
92
    public static function payload(array $payloadObject = [])
93
    {
94
        if (self::isAnonymousScope($payloadObject)) {
95
            return true;
96
        }
97
98
        self::iss($payloadObject);
99
        self::sub($payloadObject);
100
        self::iat($payloadObject);
101
        self::nbf($payloadObject);
102
        self::exp($payloadObject);
103
104
        if ((true === in_array(false, self::$isPayloadValid))) {
105
            self::unauthorised();
106
        }
107
        return true;
108
    }
109
110
    /**
111
     * Check if the scope is anonymous
112
     * @return boolean
113
     */
114
    private static function isAnonymousScope($payloadObject)
115
    {
116
        return (isset($payloadObject['scope']) && $payloadObject['scope'] == 'anonymous');
117
    }
118
119
    /**
120
     * [signature - Validate the signature object]
121
     * Third segment of the token
122
     * @return void
123
     * @throws \responsible\core\exception\responsibleException
124
     */
125
    public static function signature($jwtHead, $jwtPayload, $signature, $key)
126
    {
127
        if (
128
            empty($jwtHead) ||
129
            empty($jwtPayload) ||
130
            empty($signature) ||
131
            empty($key)
132
        ) {
133
            self::unauthorised();
134
        }
135
136
        $cipher = new encoder\cipher();
137
        $algo = parent::getAlgorithm();
138
139
        $hashed = $cipher->encode(
140
            $cipher->hash(
141
                $algo['hash'],
142
                $jwtHead . '.' . $jwtPayload,
143
                $key
144
            )
145
        );
146
147
        if (!$cipher->hashCompare($signature, $hashed)) {
148
            self::unauthorised();
149
        }
150
    }
151
152
    /**
153
     * [typ Issuer claim]
154
     *
155
     * @return bool
156
     */
157
    public static function typ($headObject)
158
    {
159
        if (
160
            !isset($headObject['typ']) ||
161
            (isset($headObject['typ']) && empty($headObject))
162
        ) {
163
            return false;
164
        }
165
        return true;
166
    }
167
168
    /**
169
     * [alg Issuer claim]
170
     *
171
     * @return bool
172
     */
173
    public static function alg($headObject)
174
    {
175
        if (
176
            !isset($headObject['alg']) ||
177
            (isset($headObject['alg']) && empty($headObject)) &&
178
            (self::getAlgorithm()['header'] === $headObject['alg'])
179
        ) {
180
            return false;
181
        }
182
183
        return true;
184
    }
185
186
    /**
187
     * [iss Issuer claim]
188
     *
189
     * @return bool
190
     */
191
    public static function iss($payloadObject)
192
    {
193
        if (
194
            !isset($payloadObject['iss']) ||
195
            (isset($payloadObject['iss']) && empty($payloadObject))
196
        ) {
197
            return false;
198
        }
199
200
        $router = new route\router();
201
        $router->route();
202
203
        if ($payloadObject['iss'] !== $router->getIssuer(true)) {
204
            return false;
205
        }
206
207
        self::$isPayloadValid['iss'] = true;
208
        return true;
209
    }
210
211
    /**
212
     * [sub Subject claim]
213
     * The Responsible API uses the "Subject" claim as a placeholder for account Ids
214
     *
215
     * @return bool
216
     */
217
    public static function sub($payloadObject)
218
    {
219
        $server = new server([], parent::$options);
220
        if ($server->isMockTest()) {
221
            return self::$isPayloadValid['sub'] = true;
222
        }
223
224
        // @codeCoverageIgnoreStart
225
        if (
226
            !isset($payloadObject['sub']) ||
227
            (isset($payloadObject['sub']) && empty($payloadObject))
228
        ) {
229
            return false;
230
        }
231
232
        $account = (object) (new user\user())
233
            ->setOptions(parent::$options)
234
            ->load($payloadObject['sub'], ['refreshToken' => false])
235
        ;
236
237
        if (empty($account)) {
238
            return false;
239
        } else {
240
            if (!isset($account->account_id)) {
241
                return false;
242
            }
243
244
            if ((int) $account->account_id !== (int) $payloadObject['sub']) {
245
                return false;
246
            }
247
        }
248
249
        self::$isPayloadValid['sub'] = true;
250
        return true;
251
        // @codeCoverageIgnoreEnd
252
    }
253
254
    /**
255
     * [iat Issued at claim]
256
     *
257
     * @return bool
258
     */
259
    public static function iat($payloadObject)
260
    {
261
        if (
262
            !isset($payloadObject['iat']) ||
263
            (isset($payloadObject['iat']) && empty($payloadObject))
264
        ) {
265
            return false;
266
        }
267
268
        if ($payloadObject['iat'] > self::getTimestamp()) {
269
            (new exception\errorException())
270
                ->setOptions(parent::$options)
271
                ->message(self::messages('not_ready'))
272
                ->error('NO_CONTENT');
273
        }
274
275
        self::$isPayloadValid['iat'] = true;
276
        return true;
277
    }
278
279
    /**
280
     * [nbf Not before claim]
281
     *
282
     * @return bool
283
     */
284
    public static function nbf($payloadObject)
285
    {
286
        if (
287
            !isset($payloadObject['nbf']) ||
288
            (isset($payloadObject['nbf']) && empty($payloadObject))
289
        ) {
290
            return false;
291
        }
292
293
        if ($payloadObject['nbf'] > self::getTimestamp()) {
294
            (new exception\errorException())
295
                ->setOptions(parent::$options)
296
                ->message(self::messages('not_ready'))
297
                ->error('NO_CONTENT');
298
        }
299
300
        self::$isPayloadValid['nbf'] = true;
301
        return true;
302
    }
303
304
    /**
305
     * [exp Expiration claim this optional so if its not set return true]
306
     *
307
     * @return bool
308
     */
309
    public static function exp($payloadObject)
310
    {
311
        if (
312
            !isset($payloadObject['exp']) ||
313
            (isset($payloadObject['exp']) && empty($payloadObject))
314
        ) {
315
            return true;
316
        }
317
318
        if ($payloadObject['exp'] <= (int) (self::$TIMESTAMP - self::$LEEWAY)) {
319
            self::unauthorised();
320
        }
321
322
        self::$isPayloadValid['exp'] = true;
323
        return true;
324
    }
325
326
    /**
327
     * [leeway Inherit the leeway offset]
328
     * @param  int $leeway [integer in seconds]
329
     * @return void
330
     */
331
    public static function leeway($leeway)
332
    {
333
        self::$LEEWAY = $leeway;
334
    }
335
336
    /**
337
     * [timestamp Inherit the current timestamp (now)]
338
     * @param  int $timestamp [integer in seconds]
339
     * @return void
340
     */
341
    public static function timestamp($timestamp)
342
    {
343
        self::$TIMESTAMP = $timestamp;
344
    }
345
346
    /**
347
     * [getTimestamp Add both the timestamp (now) and the leeway]
348
     * @return int
349
     */
350
    private static function getTimestamp()
351
    {
352
        return (int) (self::$TIMESTAMP + self::$LEEWAY);
353
    }
354
}
355