moodle-auth_jwt/classes/core_jwt_manager.php
Kumi 92ed01adc5
Some checks failed
ci / ci (push) Failing after 0s
fix(jwt): log decode errors for better debugging
Added error logging to capture JWT decode exceptions, aiding in pinpointing issues during authentication. This change improves troubleshooting and enhances the overall robustness of the JWT handling process.
2024-06-25 19:37:22 +02:00

142 lines
3.8 KiB
PHP

<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace auth_jwt;
require_once(__DIR__ . '/../vendor/autoload.php');
use \Firebase\JWT\JWT;
use \Firebase\JWT\Key;
/**
* Key manager class.
*
* @package auth_jwt
* @copyright 2016 Dmitrii Metelkin (dmitriim@catalyst-au.net), 2024 Kumi Systems e.U.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_jwt_manager
{
/**
* Default life time of the user key in seconds.
*/
const DEFAULT_KEY_LIFE_TIME_IN_SECONDS = 60;
/**
* Config object.
*
* @var \stdClass
*/
protected $config;
/**
* Constructor.
*
* @param \stdClass $config
*/
public function __construct(\stdClass $config)
{
$this->config = $config;
}
/**
* Create a user key.
*
* @param int $userid User ID.
* @param null|array $allowedips A list of allowed ips for this key.
*
* @return string Generated key.
*/
public function create_key($userid, $allowedips = null)
{
if (isset($this->config->keylifetime) && (int)$this->config->keylifetime > 0) {
$validuntil = time() + $this->config->keylifetime;
} else {
$validuntil = time() + self::DEFAULT_KEY_LIFE_TIME_IN_SECONDS;
}
$payload = [
'userid' => $userid,
'exp' => $validuntil
];
if ($allowedips) {
$payload['allowedips'] = $allowedips;
}
$secret = $this->config->jwtsecret;
return JWT::encode($payload, $secret, 'HS256');
}
/**
* Validates key and returns key data object if valid.
*
* @param string $keyvalue User key value.
*
* @return object Key object including userid property.
*
* @throws \moodle_exception If provided key is not valid.
*/
public function validate_key($keyvalue)
{
$secret = $this->config->jwtsecret;
try {
$decoded = JWT::decode($keyvalue, new Key($secret, 'HS256'));
} catch (\Exception $e) {
error_log('JWT decode error: ' . $e->getMessage());
throw new \moodle_exception('invalidkey');
}
if (!empty($decoded->exp) && $decoded->exp < time()) {
throw new \moodle_exception('expiredkey');
}
$this->validate_ip_address($decoded);
return $decoded;
}
/**
* Validates key IP address and returns true if valid.
*
* @param object $key Key object including userid property.
*
* @throws \moodle_exception If provided key is not valid.
*/
protected function validate_ip_address($key)
{
if (empty($key->allowedips)) {
return true;
}
$remoteaddr = getremoteaddr(null);
if (empty($remoteaddr)) {
throw new \moodle_exception('noip', 'auth_jwt');
}
foreach ($key->allowedips as $allowedip) {
if (address_in_subnet($remoteaddr, $allowedip)) {
return true;
}
}
throw new \moodle_exception('ipmismatch', 'error', '', null, "Remote address: $remoteaddr\nKey IP: " . implode(', ', $key->allowedips));
}
}