Merge branch 'MDL-71712-master' of https://github.com/aanabit/moodle

This commit is contained in:
Andrew Nicols
2022-02-07 09:53:09 +08:00
14 changed files with 355 additions and 93 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met:
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Neuman Vong nor the names of other
* Neither the name of the copyright holder nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
+109 -12
View File
@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/firebase/php-jwt.png?branch=master)](https://travis-ci.org/firebase/php-jwt)
![Build Status](https://github.com/firebase/php-jwt/actions/workflows/tests.yml/badge.svg)
[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt)
[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt)
[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt)
@@ -16,11 +16,18 @@ Use composer to manage your dependencies and download PHP-JWT:
composer require firebase/php-jwt
```
Optionally, install the `paragonie/sodium_compat` package from composer if your
php is < 7.2 or does not have libsodium installed:
```bash
composer require paragonie/sodium_compat
```
Example
-------
```php
<?php
use \Firebase\JWT\JWT;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$key = "example_key";
$payload = array(
@@ -36,8 +43,8 @@ $payload = array(
* https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
* for a list of spec-compliant algorithms.
*/
$jwt = JWT::encode($payload, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));
$jwt = JWT::encode($payload, $key, 'HS256');
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
print_r($decoded);
@@ -56,15 +63,13 @@ $decoded_array = (array) $decoded;
* Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
*/
JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, $key, array('HS256'));
?>
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
```
Example with RS256 (openssl)
----------------------------
```php
<?php
use \Firebase\JWT\JWT;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
@@ -103,7 +108,7 @@ $payload = array(
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, $publicKey, array('RS256'));
$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
/*
NOTE: This will now be an object instead of an associative array. To get
@@ -112,12 +117,104 @@ $decoded = JWT::decode($jwt, $publicKey, array('RS256'));
$decoded_array = (array) $decoded;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
?>
```
Example with a passphrase
-------------------------
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// Your passphrase
$passphrase = '[YOUR_PASSPHRASE]';
// Your private key file with passphrase
// Can be generated with "ssh-keygen -t rsa -m pem"
$privateKeyFile = '/path/to/key-with-passphrase.pem';
// Create a private key of type "resource"
$privateKey = openssl_pkey_get_private(
file_get_contents($privateKeyFile),
$passphrase
);
$payload = array(
"iss" => "example.org",
"aud" => "example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";
// Get public key from the private key, or pull from from a file.
$publicKey = openssl_pkey_get_details($privateKey)['key'];
$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
```
Example with EdDSA (libsodium and Ed25519 signature)
----------------------------
```php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// Public and private keys are expected to be Base64 encoded. The last
// non-empty line is used so that keys can be generated with
// sodium_crypto_sign_keypair(). The secret keys generated by other tools may
// need to be adjusted to match the input expected by libsodium.
$keyPair = sodium_crypto_sign_keypair();
$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair));
$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair));
$payload = array(
"iss" => "example.org",
"aud" => "example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
$jwt = JWT::encode($payload, $privateKey, 'EdDSA');
echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
````
Using JWKs
----------
```php
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
// Set of keys. The "keys" key is required. For example, the JSON response to
// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
$jwks = ['keys' => []];
// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
// objects. Pass this as the second parameter to JWT::decode.
JWT::decode($payload, JWK::parseKeySet($jwks));
```
Changelog
---------
#### 6.0.0 / 2022-01-24
- **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v5.5.1) for more information.
- New Key object to prevent key/algorithm type confusion (#365)
- Add JWK support (#273)
- Add ES256 support (#256)
- Add ES384 support (#324)
- Add Ed25519 support (#343)
#### 5.0.0 / 2017-06-26
- Support RS384 and RS512.
See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)!
+3
View File
@@ -22,6 +22,9 @@
"require": {
"php": ">=5.3.0"
},
"suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
+1
View File
@@ -1,4 +1,5 @@
<?php
namespace Firebase\JWT;
class BeforeValidException extends \UnexpectedValueException
+1
View File
@@ -1,4 +1,5 @@
<?php
namespace Firebase\JWT;
class ExpiredException extends \UnexpectedValueException
+12 -5
View File
@@ -3,6 +3,7 @@
namespace Firebase\JWT;
use DomainException;
use InvalidArgumentException;
use UnexpectedValueException;
/**
@@ -24,7 +25,7 @@ class JWK
*
* @param array $jwks The JSON Web Key Set as an associative array
*
* @return array An associative array that represents the set of keys
* @return array<string, Key> An associative array of key IDs (kid) to Key objects
*
* @throws InvalidArgumentException Provided JWK Set is empty
* @throws UnexpectedValueException Provided JWK Set was invalid
@@ -62,7 +63,7 @@ class JWK
*
* @param array $jwk An individual JWK
*
* @return resource|array An associative array that represents the key
* @return Key The key object for the JWK
*
* @throws InvalidArgumentException Provided JWK is empty
* @throws UnexpectedValueException Provided JWK was invalid
@@ -70,7 +71,7 @@ class JWK
*
* @uses createPemFromModulusAndExponent
*/
private static function parseKey(array $jwk)
public static function parseKey(array $jwk)
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
@@ -78,10 +79,16 @@ class JWK
if (!isset($jwk['kty'])) {
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
}
if (!isset($jwk['alg'])) {
// The "alg" parameter is optional in a KTY, but is required for parsing in
// this library. Add it manually to your JWK array if it doesn't already exist.
// @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
throw new UnexpectedValueException('JWK must contain an "alg" parameter');
}
switch ($jwk['kty']) {
case 'RSA':
if (\array_key_exists('d', $jwk)) {
if (!empty($jwk['d'])) {
throw new UnexpectedValueException('RSA private keys are not supported');
}
if (!isset($jwk['n']) || !isset($jwk['e'])) {
@@ -95,7 +102,7 @@ class JWK
'OpenSSL error: ' . \openssl_error_string()
);
}
return $publicKey;
return new Key($publicKey, $jwk['alg']);
default:
// Currently only RSA is supported
break;
+154 -66
View File
@@ -2,10 +2,13 @@
namespace Firebase\JWT;
use \DomainException;
use \InvalidArgumentException;
use \UnexpectedValueException;
use \DateTime;
use ArrayAccess;
use DomainException;
use Exception;
use InvalidArgumentException;
use OpenSSLAsymmetricKey;
use UnexpectedValueException;
use DateTime;
/**
* JSON Web Token implementation, based on this spec:
@@ -22,16 +25,19 @@ use \DateTime;
*/
class JWT
{
const ASN1_INTEGER = 0x02;
const ASN1_SEQUENCE = 0x10;
const ASN1_BIT_STRING = 0x03;
// const ASN1_INTEGER = 0x02;
// const ASN1_SEQUENCE = 0x10;
// const ASN1_BIT_STRING = 0x03;
private static $asn1Integer = 0x02;
private static $asn1Sequence = 0x10;
private static $asn1BitString = 0x03;
/**
* When checking nbf, iat or expiration times,
* we want to provide some extra leeway time to
* account for clock skew.
*/
public static $leeway = 180;
public static $leeway = 0;
/**
* Allow the current timestamp to be specified.
@@ -42,6 +48,7 @@ class JWT
public static $timestamp = null;
public static $supported_algs = array(
'ES384' => array('openssl', 'SHA384'),
'ES256' => array('openssl', 'SHA256'),
'HS256' => array('hash_hmac', 'SHA256'),
'HS384' => array('hash_hmac', 'SHA384'),
@@ -49,19 +56,23 @@ class JWT
'RS256' => array('openssl', 'SHA256'),
'RS384' => array('openssl', 'SHA384'),
'RS512' => array('openssl', 'SHA512'),
'EdDSA' => array('sodium_crypto', 'EdDSA'),
);
/**
* Decodes a JWT string into a PHP object.
*
* @param string $jwt The JWT
* @param string|array|resource $key The key, or map of keys.
* @param Key|array<string, Key> $keyOrKeyArray The Key or associative array of key IDs (kid) to Key objects.
* If the algorithm used is asymmetric, this is the public key
* @param array $allowed_algs List of supported verification algorithms
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* Each Key object contains an algorithm and matching key.
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
* 'HS512', 'RS256', 'RS384', and 'RS512'
*
* @return object The JWT's payload as a PHP object
*
* @throws InvalidArgumentException Provided key/key-array was empty
* @throws DomainException Provided JWT is malformed
* @throws UnexpectedValueException Provided JWT was invalid
* @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
* @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
@@ -71,11 +82,12 @@ class JWT
* @uses jsonDecode
* @uses urlsafeB64Decode
*/
public static function decode($jwt, $key, array $allowed_algs = array())
public static function decode($jwt, $keyOrKeyArray)
{
// Validate JWT
$timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
if (empty($key)) {
if (empty($keyOrKeyArray)) {
throw new InvalidArgumentException('Key may not be empty');
}
$tks = \explode('.', $jwt);
@@ -98,27 +110,19 @@ class JWT
if (empty(static::$supported_algs[$header->alg])) {
throw new UnexpectedValueException('Algorithm not supported');
}
if (!\in_array($header->alg, $allowed_algs)) {
throw new UnexpectedValueException('Algorithm not allowed');
$key = self::getKey($keyOrKeyArray, empty($header->kid) ? null : $header->kid);
// Check the algorithm
if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {
// See issue #351
throw new UnexpectedValueException('Incorrect key for this algorithm');
}
if ($header->alg === 'ES256') {
// OpenSSL expects an ASN.1 DER sequence for ES256 signatures
if ($header->alg === 'ES256' || $header->alg === 'ES384') {
// OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
$sig = self::signatureToDER($sig);
}
if (\is_array($key) || $key instanceof \ArrayAccess) {
if (isset($header->kid)) {
if (!isset($key[$header->kid])) {
throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
}
$key = $key[$header->kid];
} else {
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}
}
// Check the signature
if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
if (!static::verify("$headb64.$bodyb64", $sig, $key->getKeyMaterial(), $header->alg)) {
throw new SignatureInvalidException('Signature verification failed');
}
@@ -150,20 +154,21 @@ class JWT
/**
* Converts and signs a PHP object or array into a JWT string.
*
* @param object|array $payload PHP object or array
* @param string $key The secret key.
* If the algorithm used is asymmetric, this is the private key
* @param string $alg The signing algorithm.
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* @param mixed $keyId
* @param array $head An array with header elements to attach
* @param object|array $payload PHP object or array
* @param string|resource $key The secret key.
* If the algorithm used is asymmetric, this is the private key
* @param string $alg The signing algorithm.
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
* 'HS512', 'RS256', 'RS384', and 'RS512'
* @param mixed $keyId
* @param array $head An array with header elements to attach
*
* @return string A signed JWT
*
* @uses jsonEncode
* @uses urlsafeB64Encode
*/
public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
public static function encode($payload, $key, $alg, $keyId = null, $head = null)
{
$header = array('typ' => 'JWT', 'alg' => $alg);
if ($keyId !== null) {
@@ -189,13 +194,14 @@ class JWT
* @param string $msg The message to sign
* @param string|resource $key The secret key
* @param string $alg The signing algorithm.
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
* 'HS512', 'RS256', 'RS384', and 'RS512'
*
* @return string An encrypted message
*
* @throws DomainException Unsupported algorithm was specified
* @throws DomainException Unsupported algorithm or bad key was specified
*/
public static function sign($msg, $key, $alg = 'HS256')
public static function sign($msg, $key, $alg)
{
if (empty(static::$supported_algs[$alg])) {
throw new DomainException('Algorithm not supported');
@@ -209,11 +215,24 @@ class JWT
$success = \openssl_sign($msg, $signature, $key, $algorithm);
if (!$success) {
throw new DomainException("OpenSSL unable to sign data");
} else {
if ($alg === 'ES256') {
$signature = self::signatureFromDER($signature, 256);
}
return $signature;
}
if ($alg === 'ES256') {
$signature = self::signatureFromDER($signature, 256);
} elseif ($alg === 'ES384') {
$signature = self::signatureFromDER($signature, 384);
}
return $signature;
case 'sodium_crypto':
if (!function_exists('sodium_crypto_sign_detached')) {
throw new DomainException('libsodium is not available');
}
try {
// The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $key));
$key = base64_decode(end($lines));
return sodium_crypto_sign_detached($msg, $key);
} catch (Exception $e) {
throw new DomainException($e->getMessage(), 0, $e);
}
}
}
@@ -229,7 +248,7 @@ class JWT
*
* @return bool
*
* @throws DomainException Invalid Algorithm or OpenSSL failure
* @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
*/
private static function verify($msg, $signature, $key, $alg)
{
@@ -250,21 +269,22 @@ class JWT
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
);
case 'sodium_crypto':
if (!function_exists('sodium_crypto_sign_verify_detached')) {
throw new DomainException('libsodium is not available');
}
try {
// The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $key));
$key = base64_decode(end($lines));
return sodium_crypto_sign_verify_detached($signature, $msg, $key);
} catch (Exception $e) {
throw new DomainException($e->getMessage(), 0, $e);
}
case 'hash_hmac':
default:
$hash = \hash_hmac($algorithm, $msg, $key, true);
if (\function_exists('hash_equals')) {
return \hash_equals($signature, $hash);
}
$len = \min(static::safeStrlen($signature), static::safeStrlen($hash));
$status = 0;
for ($i = 0; $i < $len; $i++) {
$status |= (\ord($signature[$i]) ^ \ord($hash[$i]));
}
$status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash));
return ($status === 0);
return self::constantTimeEquals($signature, $hash);
}
}
@@ -314,7 +334,12 @@ class JWT
*/
public static function jsonEncode($input)
{
$json = \json_encode($input);
if (PHP_VERSION_ID >= 50400) {
$json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
} else {
// PHP 5.3 only
$json = \json_encode($input);
}
if ($errno = \json_last_error()) {
static::handleJsonError($errno);
} elseif ($json === 'null' && $input !== null) {
@@ -352,6 +377,69 @@ class JWT
return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
}
/**
* Determine if an algorithm has been provided for each Key
*
* @param Key|array<string, Key> $keyOrKeyArray
* @param string|null $kid
*
* @throws UnexpectedValueException
*
* @return array containing the keyMaterial and algorithm
*/
private static function getKey($keyOrKeyArray, $kid = null)
{
if ($keyOrKeyArray instanceof Key) {
return $keyOrKeyArray;
}
if (is_array($keyOrKeyArray) || $keyOrKeyArray instanceof ArrayAccess) {
foreach ($keyOrKeyArray as $keyId => $key) {
if (!$key instanceof Key) {
throw new UnexpectedValueException(
'$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
. 'array of Firebase\JWT\Key keys'
);
}
}
if (!isset($kid)) {
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}
if (!isset($keyOrKeyArray[$kid])) {
throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
}
return $keyOrKeyArray[$kid];
}
throw new UnexpectedValueException(
'$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
. 'array of Firebase\JWT\Key keys'
);
}
/**
* @param string $left
* @param string $right
* @return bool
*/
public static function constantTimeEquals($left, $right)
{
if (\function_exists('hash_equals')) {
return \hash_equals($left, $right);
}
$len = \min(static::safeStrlen($left), static::safeStrlen($right));
$status = 0;
for ($i = 0; $i < $len; $i++) {
$status |= (\ord($left[$i]) ^ \ord($right[$i]));
}
$status |= (static::safeStrlen($left) ^ static::safeStrlen($right));
return ($status === 0);
}
/**
* Helper method to create a JSON error.
*
@@ -415,9 +503,9 @@ class JWT
}
return self::encodeDER(
self::ASN1_SEQUENCE,
self::encodeDER(self::ASN1_INTEGER, $r) .
self::encodeDER(self::ASN1_INTEGER, $s)
self::$asn1Sequence,
self::encodeDER(self::$asn1Integer, $r) .
self::encodeDER(self::$asn1Integer, $s)
);
}
@@ -431,7 +519,7 @@ class JWT
private static function encodeDER($type, $value)
{
$tag_header = 0;
if ($type === self::ASN1_SEQUENCE) {
if ($type === self::$asn1Sequence) {
$tag_header |= 0x20;
}
@@ -496,7 +584,7 @@ class JWT
}
// Value
if ($type == self::ASN1_BIT_STRING) {
if ($type == self::$asn1BitString) {
$pos++; // Skip the first contents octet (padding indicator)
$data = \substr($der, $pos, $len - 1);
$pos += $len - 1;
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace Firebase\JWT;
use InvalidArgumentException;
use OpenSSLAsymmetricKey;
class Key
{
/** @var string $algorithm */
private $algorithm;
/** @var string|resource|OpenSSLAsymmetricKey $keyMaterial */
private $keyMaterial;
/**
* @param string|resource|OpenSSLAsymmetricKey $keyMaterial
* @param string $algorithm
*/
public function __construct($keyMaterial, $algorithm)
{
if (
!is_string($keyMaterial)
&& !is_resource($keyMaterial)
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
) {
throw new InvalidArgumentException('Type error: $keyMaterial must be a string, resource, or OpenSSLAsymmetricKey');
}
if (empty($keyMaterial)) {
throw new InvalidArgumentException('Type error: $keyMaterial must not be empty');
}
if (!is_string($algorithm)|| empty($keyMaterial)) {
throw new InvalidArgumentException('Type error: $algorithm must be a string');
}
$this->keyMaterial = $keyMaterial;
$this->algorithm = $algorithm;
}
/**
* Return the algorithm valid for this key
*
* @return string
*/
public function getAlgorithm()
{
return $this->algorithm;
}
/**
* @return string|resource|OpenSSLAsymmetricKey
*/
public function getKeyMaterial()
{
return $this->keyMaterial;
}
}
@@ -1,4 +1,5 @@
<?php
namespace Firebase\JWT;
class SignatureInvalidException extends \UnexpectedValueException
+1 -1
View File
@@ -299,7 +299,7 @@
<location>php-jwt</location>
<name>A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to RFC 7519</name>
<license>BSD</license>
<version>5.2.0</version>
<version>6.0.0</version>
<licenseversion>3-Clause</licenseversion>
</library>
<library>
+2 -2
View File
@@ -18,6 +18,7 @@ namespace mod_bigbluebuttonbn;
use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use mod_bigbluebuttonbn\local\config;
/**
@@ -88,8 +89,7 @@ class broker {
try {
$decodedparameters = JWT::decode(
$params['signed_parameters'],
config::get('shared_secret'),
['HS256']
new Key(config::get('shared_secret'), 'HS256')
);
} catch (Exception $e) {
$error = 'Caught exception: ' . $e->getMessage();
+2 -2
View File
@@ -21,6 +21,7 @@ use cache_store;
use context_course;
use core_tag_tag;
use Exception;
use Firebase\JWT\Key;
use mod_bigbluebuttonbn\local\config;
use mod_bigbluebuttonbn\local\exceptions\bigbluebutton_exception;
use mod_bigbluebuttonbn\local\exceptions\meeting_join_exception;
@@ -432,8 +433,7 @@ class meeting {
// Verify the authenticity of the request.
$token = \Firebase\JWT\JWT::decode(
$authorization[1],
config::get('shared_secret'),
['HS512']
new Key(config::get('shared_secret'), 'HS512')
);
// Get JSON string from the body.
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die;
require_once($CFG->dirroot . '/mod/lti/locallib.php');
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use stdClass;
/**
@@ -371,8 +372,9 @@ class registration_helper {
*/
public function validate_registration_token(string $registrationtokenjwt): array {
global $DB;
// JWK::parseKeySet uses RS256 algorithm by default.
$keys = JWK::parseKeySet(jwks_helper::get_jwks());
$registrationtoken = JWT::decode($registrationtokenjwt, $keys, ['RS256']);
$registrationtoken = JWT::decode($registrationtokenjwt, $keys);
$response = [];
// Get clientid from registrationtoken.
$clientid = $registrationtoken->sub;
+6 -3
View File
@@ -55,6 +55,7 @@ use mod_lti\helper;
use moodle\mod\lti as lti;
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
use Firebase\JWT\Key;
use mod_lti\local\ltiopenid\jwks_helper;
use mod_lti\local\ltiopenid\registration_helper;
@@ -1360,14 +1361,16 @@ function lti_verify_with_keyset($jwtparam, $keyseturl, $clientid) {
throw new moodle_exception('errornocachedkeysetfound', 'mod_lti');
}
$keysetarr = json_decode($keyset, true);
// JWK::parseKeySet uses RS256 algorithm by default.
$keys = JWK::parseKeySet($keysetarr);
$jwt = JWT::decode($jwtparam, $keys, ['RS256']);
$jwt = JWT::decode($jwtparam, $keys);
} catch (Exception $e) {
// Something went wrong, so attempt to update cached keyset and then try again.
$keyset = file_get_contents($keyseturl);
$keysetarr = json_decode($keyset, true);
// JWK::parseKeySet uses RS256 algorithm by default.
$keys = JWK::parseKeySet($keysetarr);
$jwt = JWT::decode($jwtparam, $keys, ['RS256']);
$jwt = JWT::decode($jwtparam, $keys);
// If sucessful, updates the cached keyset.
$cache->set($clientid, $keyset);
}
@@ -1414,7 +1417,7 @@ function lti_verify_jwt_signature($typeid, $consumerkey, $jwtparam) {
throw new moodle_exception('No public key configured');
}
// Attemps to verify jwt with RSA key.
JWT::decode($jwtparam, $publickey, ['RS256']);
JWT::decode($jwtparam, new Key($publickey, 'RS256'));
} else if ($typeconfig['keytype'] === LTI_JWK_KEYSET) {
$keyseturl = $typeconfig['publickeyset'] ?? '';
if (empty($keyseturl)) {