moodle-auth_jwt/classes/core_jwt_manager.php
Kumi 5ae53cfc14
Some checks failed
ci / ci (push) Failing after 0s
fix: update JWT decode method to use Key object
Modified the JWT::decode method to use the Key object for decoding JWTs. This enhances security by explicitly specifying the algorithm used (HS256) and aligns with recent updates in the Firebase JWT library.
2024-06-25 19:33:02 +02:00

141 lines
3.7 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) {
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));
}
}