Subversion Repositories oidplus

Rev

Rev 1301 | Rev 1305 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
566 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
566 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
566 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
1303 daniel-mar 26
/**
27
 * Auth content store for JWT tokens ("Remember me" cookies, Automated AJAX argument, or REST Bearer)
28
 */
1301 daniel-mar 29
class OIDplusAuthContentStoreJWT extends OIDplusAuthContentStore {
566 daniel-mar 30
 
1130 daniel-mar 31
        /**
32
         * Cookie name for the JWT auth token
33
         */
585 daniel-mar 34
        const COOKIE_NAME = 'OIDPLUS_AUTH_JWT';
35
 
1130 daniel-mar 36
        /**
37
         * "Automated AJAX" plugin
38
         */
1265 daniel-mar 39
        const JWT_GENERATOR_AJAX   = 10;
1130 daniel-mar 40
        /**
1265 daniel-mar 41
         * "REST API" plugin
42
         */
43
        const JWT_GENERATOR_REST   = 20;
44
        /**
1130 daniel-mar 45
         * "Remember me" login method
46
         */
1265 daniel-mar 47
        const JWT_GENERATOR_LOGIN  = 40;
1130 daniel-mar 48
        /**
49
         * "Manually crafted" JWT tokens
50
         */
1265 daniel-mar 51
        const JWT_GENERATOR_MANUAL = 80;
585 daniel-mar 52
 
1116 daniel-mar 53
        /**
54
         * @param int $gen OIDplusAuthContentStoreJWT::JWT_GENERATOR_...
55
         * @param string $sub
56
         * @return string
57
         */
58
        private static function jwtGetBlacklistConfigKey(int $gen, string $sub): string {
1265 daniel-mar 59
                // Note: Needs to be <= 50 characters! If $gen is 2 chars, then the config key is 49 chars long
585 daniel-mar 60
                return 'jwt_blacklist_gen('.$gen.')_sub('.trim(base64_encode(md5($sub,true)),'=').')';
61
        }
62
 
1116 daniel-mar 63
        /**
1265 daniel-mar 64
         * @param int $gen
65
         */
66
        private static function generatorName($gen) {
67
                // Note: The strings are not translated, because the name is used in config keys or logs
68
                if ($gen === self::JWT_GENERATOR_AJAX)   return 'Automated AJAX calls';
69
                if ($gen === self::JWT_GENERATOR_REST)   return 'REST API';
70
                if ($gen === self::JWT_GENERATOR_LOGIN)  return 'Login ("Remember me")';
71
                if ($gen === self::JWT_GENERATOR_MANUAL) return 'Manually created';
72
                return 'Unknown generator';
73
        }
74
 
75
        /**
1116 daniel-mar 76
         * @param int $gen OIDplusAuthContentStoreJWT::JWT_GENERATOR_...
77
         * @param string $sub
78
         * @return void
79
         * @throws OIDplusException
80
         */
81
        public static function jwtBlacklist(int $gen, string $sub) {
585 daniel-mar 82
                $cfg = self::jwtGetBlacklistConfigKey($gen, $sub);
83
                $bl_time = time()-1;
84
 
1265 daniel-mar 85
                $gen_desc = self::generatorName($gen);
585 daniel-mar 86
 
1116 daniel-mar 87
                OIDplus::config()->prepareConfigKey($cfg, 'Revoke timestamp of all JWT tokens for $sub with generator $gen ($gen_desc)', "$bl_time", OIDplusConfig::PROTECTION_HIDDEN, function($value) {});
585 daniel-mar 88
                OIDplus::config()->setValue($cfg, $bl_time);
89
        }
90
 
1116 daniel-mar 91
        /**
92
         * @param int $gen OIDplusAuthContentStoreJWT::JWT_GENERATOR_...
93
         * @param string $sub
94
         * @return int
95
         * @throws OIDplusException
96
         */
97
        public static function jwtGetBlacklistTime(int $gen, string $sub): int {
585 daniel-mar 98
                $cfg = self::jwtGetBlacklistConfigKey($gen, $sub);
1116 daniel-mar 99
                return (int)OIDplus::config()->getValue($cfg,0);
585 daniel-mar 100
        }
101
 
1116 daniel-mar 102
        /**
1298 daniel-mar 103
         * We include a hash of the server-secret here (ssh = server-secret-hash), so that the JWT can be invalidated by changing the server-secret
104
         * @return string
105
         * @throws OIDplusException
106
         */
107
        private static function getSsh(): string {
108
                return OIDplus::authUtils()->makeSecret(['bb1aebd6-fe6a-11ed-a553-3c4a92df8582']);
109
        }
110
 
111
        /**
1265 daniel-mar 112
         * Do various checks if the token is allowed and not blacklisted
1116 daniel-mar 113
         * @param OIDplusAuthContentStore $contentProvider
1277 daniel-mar 114
         * @param int|null $validGenerators Bitmask which generators to allow (null = allow all)
1116 daniel-mar 115
         * @return void
116
         * @throws OIDplusException
117
         */
1277 daniel-mar 118
        private static function jwtSecurityCheck(OIDplusAuthContentStore $contentProvider, int $validGenerators=null) {
585 daniel-mar 119
                // Check if the token is intended for us
699 daniel-mar 120
                if ($contentProvider->getValue('aud','') !== OIDplus::getEditionInfo()['jwtaud']) {
585 daniel-mar 121
                        throw new OIDplusException(_L('Token has wrong audience'));
122
                }
1298 daniel-mar 123
 
124
                if ($contentProvider->getValue('oidplus_ssh', '') !== self::getSsh()) {
125
                        throw new OIDplusException(_L('"Server Secret" was changed; therefore the JWT is not valid anymore'));
126
                }
127
 
585 daniel-mar 128
                $gen = $contentProvider->getValue('oidplus_generator', -1);
129
 
130
                $has_admin = $contentProvider->isAdminLoggedIn();
131
                $has_ra = $contentProvider->raNumLoggedIn() > 0;
132
 
133
                // Check if the token generator is allowed
134
                if ($gen === self::JWT_GENERATOR_AJAX) {
135
                        if (($has_admin) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_AJAX_ADMIN', true)) {
635 daniel-mar 136
                                // Generator: plugins/viathinksoft/adminPages/910_automated_ajax_calls/OIDplusPageAdminAutomatedAJAXCalls.class.php
585 daniel-mar 137
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_AJAX_ADMIN'));
138
                        }
139
                        if (($has_ra) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_AJAX_USER', true)) {
635 daniel-mar 140
                                // Generator: plugins/viathinksoft/raPages/910_automated_ajax_calls/OIDplusPageRaAutomatedAJAXCalls.class.php
585 daniel-mar 141
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_AJAX_USER'));
142
                        }
143
                }
1265 daniel-mar 144
                else if ($gen === self::JWT_GENERATOR_REST) {
145
                        if (($has_admin) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_ADMIN', true)) {
146
                                // Generator: plugins/viathinksoft/adminPages/911_rest_api/OIDplusPageAdminRestApi.class.php
147
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_ADMIN'));
148
                        }
149
                        if (($has_ra) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_REST_USER', true)) {
150
                                // Generator: plugins/viathinksoft/raPages/911_rest_api/OIDplusPageRaRestApi.class.php
151
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_REST_USER'));
152
                        }
153
                }
585 daniel-mar 154
                else if ($gen === self::JWT_GENERATOR_LOGIN) {
155
                        // Used for feature "Remember me" (use JWT token in a cookie as alternative to PHP session):
156
                        // - No PHP session will be used
157
                        // - Session will not be bound to IP address (therefore, you can switch between mobile/WiFi for example)
158
                        // - No server-side session needed
159
                        if (($has_admin) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_ADMIN', true)) {
160
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_LOGIN_ADMIN'));
161
                        }
162
                        if (($has_ra) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
163
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_LOGIN_USER'));
164
                        }
165
                }
166
                else if ($gen === self::JWT_GENERATOR_MANUAL) {
1300 daniel-mar 167
                        // Generator: "hand-crafted" tokens
168
                        if (($has_admin) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_MANUAL_ADMIN', false)) {
169
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_MANUAL_ADMIN'));
585 daniel-mar 170
                        }
1300 daniel-mar 171
                        if (($has_ra) && !OIDplus::baseConfig()->getValue('JWT_ALLOW_MANUAL_USER', false)) {
172
                                throw new OIDplusException(_L('The administrator has disabled this feature. (Base configuration setting %1).','JWT_ALLOW_MANUAL_USER'));
173
                        }
585 daniel-mar 174
                } else {
175
                        throw new OIDplusException(_L('Token generator %1 not recognized',$gen));
176
                }
177
 
178
                // Make sure that the IAT (issued at time) isn't in a blacklisted timeframe
179
                // When an user believes that a token was compromised, then they can blacklist the tokens identified by their "iat" ("Issued at") property
180
                // When a user logs out of a "remember me" session, the JWT token will be blacklisted as well
181
                // Small side effect: All "remember me" sessions of that user will be revoked then
1281 daniel-mar 182
                $iat = $contentProvider->getValue('iat',0);
183
                if (($iat-120/*leeway 2min*/) > time()) {
184
                        // Token was created in the future. Something is wrong!
185
                        throw new OIDplusException(_L('JWT Token cannot be verified because the server time is wrong'));
186
                }
585 daniel-mar 187
                $sublist = $contentProvider->loggedInRaList();
1281 daniel-mar 188
                $usernames = array();
189
                foreach ($sublist as $sub) {
190
                        $usernames[] = $sub->raEmail();
585 daniel-mar 191
                }
1281 daniel-mar 192
                if ($has_admin) $usernames[] = 'admin';
193
                foreach ($usernames as $username) {
194
                        $bl_time = self::jwtGetBlacklistTime($gen, $username);
585 daniel-mar 195
                        if ($iat <= $bl_time) {
1281 daniel-mar 196
                                // Token is blacklisted (it was created before the last blacklist time)
585 daniel-mar 197
                                throw new OIDplusException(_L('The JWT token was blacklisted on %1. Please generate a new one',date('d F Y, H:i:s',$bl_time)));
198
                        }
199
                }
200
 
201
                // Optional feature: Limit the JWT to a specific IP address
202
                // Currently not used in OIDplus
1300 daniel-mar 203
                $ip = $contentProvider->getValue('oidplus_limit_ip','');
585 daniel-mar 204
                if ($ip !== '') {
205
                        if (isset($_SERVER['REMOTE_ADDR']) && ($ip !== $_SERVER['REMOTE_ADDR'])) {
206
                                throw new OIDplusException(_L('Your IP address is not allowed to use this token'));
207
                        }
208
                }
209
 
1265 daniel-mar 210
                // Checks if JWT are dependent on the generator
1277 daniel-mar 211
                if (!is_null($validGenerators)) {
1265 daniel-mar 212
                        if (($gen & $validGenerators) === 0) {
213
                                throw new OIDplusException(_L('This kind of JWT token (%1) cannot be used in this request type', self::generatorName($gen)));
585 daniel-mar 214
                        }
215
                }
216
        }
217
 
218
        // Override abstract functions
219
 
1116 daniel-mar 220
        /**
1301 daniel-mar 221
         * @var array
222
         */
223
        protected $content = array();
224
 
225
        /**
226
         * @param string $name
227
         * @param mixed|null $default
228
         * @return mixed|null
229
         */
230
        public function getValue(string $name, $default = NULL) {
231
                return $this->content[$name] ?? $default;
232
        }
233
 
234
        /**
235
         * @param string $name
236
         * @param mixed $value
1116 daniel-mar 237
         * @return void
238
         */
1301 daniel-mar 239
        public function setValue(string $name, $value) {
240
                $this->content[$name] = $value;
241
        }
242
 
243
        /**
244
         * @param string $name
245
         * @return bool
246
         */
247
        public function exists(string $name): bool {
248
                return isset($this->content[$name]);
249
        }
250
 
251
        /**
252
         * @param string $name
253
         * @return void
254
         */
255
        public function delete(string $name) {
256
                unset($this->content[$name]);
257
        }
258
 
259
        /**
260
         * @return void
261
         */
585 daniel-mar 262
        public function activate() {
620 daniel-mar 263
                // Send cookie at the end of the HTTP request, in case there are multiple activate() calls
639 daniel-mar 264
                OIDplus::register_shutdown_function(array($this,'activateNow'));
620 daniel-mar 265
        }
266
 
1116 daniel-mar 267
        /**
268
         * @return void
269
         * @throws OIDplusException
270
         */
620 daniel-mar 271
        public function activateNow() {
585 daniel-mar 272
                $token = $this->getJWTToken();
273
                $exp = $this->getValue('exp',0);
274
                OIDplus::cookieUtils()->setcookie(self::COOKIE_NAME, $token, $exp, false);
275
        }
276
 
1116 daniel-mar 277
        /**
278
         * @return void
279
         * @throws OIDplusException
280
         */
585 daniel-mar 281
        public function destroySession() {
282
                OIDplus::cookieUtils()->unsetcookie(self::COOKIE_NAME);
283
        }
284
 
1116 daniel-mar 285
        /**
286
         * @param string $email
287
         * @return void
288
         * @throws OIDplusException
289
         */
290
        public function raLogout(string $email) {
585 daniel-mar 291
                $gen = $this->getValue('oidplus_generator', -1);
292
                if ($gen >= 0) self::jwtBlacklist($gen, $email);
293
                parent::raLogout($email);
294
        }
295
 
1116 daniel-mar 296
        /**
297
         * @param string $email
298
         * @param string $loginfo
299
         * @return void
300
         * @throws OIDplusException
301
         */
302
        public function raLogoutEx(string $email, string &$loginfo) {
585 daniel-mar 303
                $this->raLogout($email);
304
                $loginfo = 'from JWT session';
305
        }
306
 
1116 daniel-mar 307
        /**
308
         * @return void
309
         * @throws OIDplusException
310
         */
585 daniel-mar 311
        public function adminLogout() {
312
                $gen = $this->getValue('oidplus_generator', -1);
313
                if ($gen >= 0) self::jwtBlacklist($gen, 'admin');
314
                parent::adminLogout();
315
        }
316
 
1116 daniel-mar 317
        /**
318
         * @param string $loginfo
319
         * @return void
320
         * @throws OIDplusException
321
         */
322
        public function adminLogoutEx(string &$loginfo) {
585 daniel-mar 323
                $this->adminLogout();
324
                $loginfo = 'from JWT session';
325
        }
326
 
620 daniel-mar 327
        private static $contentProvider = null;
1116 daniel-mar 328
 
329
        /**
330
         * @return OIDplusAuthContentStore|null
331
         * @throws OIDplusException
332
         */
333
        public static function getActiveProvider()/*: ?OIDplusAuthContentStore*/ {
620 daniel-mar 334
                if (!self::$contentProvider) {
585 daniel-mar 335
 
1265 daniel-mar 336
                        $tmp = null;
337
                        $silent_error = false;
585 daniel-mar 338
 
1265 daniel-mar 339
                        try {
585 daniel-mar 340
 
1265 daniel-mar 341
                                $rel_url = substr($_SERVER['REQUEST_URI'], strlen(OIDplus::webpath(null, OIDplus::PATH_RELATIVE_TO_ROOT)));
342
                                if (str_starts_with($rel_url, 'rest/')) { // <== TODO: Find a way how to move this into the plugin, since REST does not belong to the core.
343
 
344
                                        // REST may only use Bearer Authentication
345
                                        $bearer = getBearerToken();
346
                                        if (!is_null($bearer)) {
347
                                                $silent_error = false;
348
                                                $tmp = new OIDplusAuthContentStoreJWT();
349
                                                $tmp->loadJWT($bearer);
350
                                                self::jwtSecurityCheck($tmp, self::JWT_GENERATOR_REST | self::JWT_GENERATOR_MANUAL);
585 daniel-mar 351
                                        }
1265 daniel-mar 352
 
353
                                } else {
354
 
355
                                        // A web-visitor (HTML and AJAX, but not REST) can use a JWT "remember me" Cookie
356
                                        if (isset($_COOKIE[self::COOKIE_NAME])) {
357
                                                $silent_error = true;
358
                                                $tmp = new OIDplusAuthContentStoreJWT();
359
                                                $tmp->loadJWT($_COOKIE[self::COOKIE_NAME]);
360
                                                self::jwtSecurityCheck($tmp, self::JWT_GENERATOR_LOGIN | self::JWT_GENERATOR_MANUAL);
361
                                        }
362
 
363
                                        // AJAX may additionally use GET/POST automated AJAX (in addition to the normal JWT "remember me" Cookie)
364
                                        if (isset($_SERVER['SCRIPT_FILENAME']) && (strtolower(basename($_SERVER['SCRIPT_FILENAME'])) !== 'ajax.php')) {
365
                                                if (isset($_POST[self::COOKIE_NAME])) {
366
                                                        $silent_error = false;
367
                                                        $tmp = new OIDplusAuthContentStoreJWT();
368
                                                        $tmp->loadJWT($_POST[self::COOKIE_NAME]);
369
                                                        self::jwtSecurityCheck($tmp, self::JWT_GENERATOR_AJAX | self::JWT_GENERATOR_MANUAL);
370
                                                }
371
                                                if (isset($_GET[self::COOKIE_NAME])) {
372
                                                        $silent_error = false;
373
                                                        $tmp = new OIDplusAuthContentStoreJWT();
374
                                                        $tmp->loadJWT($_GET[self::COOKIE_NAME]);
375
                                                        self::jwtSecurityCheck($tmp, self::JWT_GENERATOR_AJAX | self::JWT_GENERATOR_MANUAL);
376
                                                }
377
                                        }
378
 
585 daniel-mar 379
                                }
380
 
1265 daniel-mar 381
                        } catch (\Exception $e) {
382
                                if (!$silent_error) {
383
                                        // Most likely an AJAX request. We can throw an Exception
384
                                        throw new OIDplusException(_L('The JWT token was rejected: %1',$e->getMessage()));
385
                                } else {
386
                                        // Most likely an expired Cookie/Login session. We must not throw an Exception, otherwise we will break jsTree
387
                                        OIDplus::cookieUtils()->unsetcookie(self::COOKIE_NAME);
388
                                        return null;
389
                                }
585 daniel-mar 390
                        }
1265 daniel-mar 391
 
392
                        self::$contentProvider = $tmp;
585 daniel-mar 393
                }
394
 
620 daniel-mar 395
                return self::$contentProvider;
585 daniel-mar 396
        }
397
 
1116 daniel-mar 398
        /**
399
         * @param string $email
400
         * @param string $loginfo
401
         * @return void
402
         * @throws OIDplusException
403
         */
404
        public function raLoginEx(string $email, string &$loginfo) {
585 daniel-mar 405
                if (is_null(self::getActiveProvider())) {
406
                        $this->raLogin($email);
407
                        $loginfo = 'into new JWT session';
620 daniel-mar 408
                        self::$contentProvider = $this;
585 daniel-mar 409
                } else {
410
                        $gen = $this->getValue('oidplus_generator',-1);
411
                        switch ($gen) {
412
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_AJAX :
1265 daniel-mar 413
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST :
585 daniel-mar 414
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_MANUAL :
415
                                        throw new OIDplusException(_L('This kind of JWT token cannot be altered. Therefore you cannot do this action.'));
416
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN :
417
                                        if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_USER', true)) {
418
                                                throw new OIDplusException(_L('You cannot add this login credential to your existing "remember me" session. You need to log-out first.'));
419
                                        }
420
                                        break;
421
                                default:
422
                                        assert(false); // This cannot happen because jwtSecurityCheck will check for unknown generators
423
                                        break;
424
                        }
425
                        $this->raLogin($email);
426
                        $loginfo = 'into existing JWT session';
427
                }
428
        }
429
 
1116 daniel-mar 430
        /**
431
         * @param string $loginfo
432
         * @return void
433
         * @throws OIDplusException
434
         */
435
        public function adminLoginEx(string &$loginfo) {
585 daniel-mar 436
                if (is_null(self::getActiveProvider())) {
437
                        $this->adminLogin();
438
                        $loginfo = 'into new JWT session';
620 daniel-mar 439
                        self::$contentProvider = $this;
585 daniel-mar 440
                } else {
441
                        $gen = $this->getValue('oidplus_generator',-1);
442
                        switch ($gen) {
443
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_AJAX :
1265 daniel-mar 444
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_REST :
585 daniel-mar 445
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_MANUAL :
446
                                        throw new OIDplusException(_L('This kind of JWT token cannot be altered. Therefore you cannot do this action.'));
447
                                case OIDplusAuthContentStoreJWT::JWT_GENERATOR_LOGIN :
448
                                        if (!OIDplus::baseConfig()->getValue('JWT_ALLOW_LOGIN_ADMIN', true)) {
449
                                                throw new OIDplusException(_L('You cannot add this login credential to your existing "remember me" session. You need to log-out first.'));
450
                                        }
451
                                        break;
452
                                default:
453
                                        assert(false); // This cannot happen because jwtSecurityCheck will check for unknown generators
454
                                        break;
455
                        }
456
                        $this->adminLogin();
457
                        $loginfo = 'into existing JWT session';
458
                }
459
        }
460
 
566 daniel-mar 461
        // Individual functions
462
 
1116 daniel-mar 463
        /**
1265 daniel-mar 464
         * Decode the JWT. In this step, the signature as well as EXP/NBF times will be checked
1116 daniel-mar 465
         * @param string $jwt
466
         * @return void
467
         * @throws OIDplusException
468
         */
469
        public function loadJWT(string $jwt) {
571 daniel-mar 470
                \Firebase\JWT\JWT::$leeway = 60; // leeway in seconds
570 daniel-mar 471
                if (OIDplus::getPkiStatus()) {
830 daniel-mar 472
                        $pubKey = OIDplus::getSystemPublicKey();
1298 daniel-mar 473
                        $k = new \Firebase\JWT\Key($pubKey, 'RS256'); // RSA+SHA256 is hardcoded in getPkiStatus() generation
679 daniel-mar 474
                        $this->content = (array) \Firebase\JWT\JWT::decode($jwt, $k);
570 daniel-mar 475
                } else {
1283 daniel-mar 476
                        $key = OIDplus::authUtils()->makeSecret(['0be35e52-f4ef-11ed-b67e-3c4a92df8582']);
826 daniel-mar 477
                        $key = hash_pbkdf2('sha512', $key, '', 10000, 32/*256bit*/, false);
679 daniel-mar 478
                        $k = new \Firebase\JWT\Key($key, 'HS512'); // HMAC+SHA512 is hardcoded here
479
                        $this->content = (array) \Firebase\JWT\JWT::decode($jwt, $k);
570 daniel-mar 480
                }
566 daniel-mar 481
        }
482
 
1116 daniel-mar 483
        /**
484
         * @return string
485
         * @throws OIDplusException
486
         */
487
        public function getJWTToken(): string {
566 daniel-mar 488
                $payload = $this->content;
1300 daniel-mar 489
                $payload["oidplus_ssh"] = self::getSsh(); // SSH = Server Secret Hash
699 daniel-mar 490
                $payload["iss"] = OIDplus::getEditionInfo()['jwtaud'];
491
                $payload["aud"] = OIDplus::getEditionInfo()['jwtaud'];
570 daniel-mar 492
                $payload["jti"] = gen_uuid();
566 daniel-mar 493
                $payload["iat"] = time();
570 daniel-mar 494
 
495
                if (OIDplus::getPkiStatus()) {
830 daniel-mar 496
                        $privKey = OIDplus::getSystemPrivateKey();
1298 daniel-mar 497
                        return \Firebase\JWT\JWT::encode($payload, $privKey, 'RS256'); // RSA+SHA256 is hardcoded in getPkiStatus() generation
570 daniel-mar 498
                } else {
1283 daniel-mar 499
                        $key = OIDplus::authUtils()->makeSecret(['0be35e52-f4ef-11ed-b67e-3c4a92df8582']);
826 daniel-mar 500
                        $key = hash_pbkdf2('sha512', $key, '', 10000, 32/*256bit*/, false);
679 daniel-mar 501
                        return \Firebase\JWT\JWT::encode($payload, $key, 'HS512'); // HMAC+SHA512 is hardcoded here
570 daniel-mar 502
                }
566 daniel-mar 503
        }
504
 
570 daniel-mar 505
}