Merge remote-tracking branch 'origin/support/3.0' into develop

# Conflicts:
#	composer.json
#	composer.lock
#	lib/composer/autoload_files.php
#	lib/composer/autoload_real.php
#	lib/composer/autoload_static.php
#	lib/composer/installed.json
#	lib/composer/installed.php
#	lib/firebase/php-jwt/README.md
#	lib/firebase/php-jwt/src/CachedKeySet.php
#	lib/firebase/php-jwt/src/JWK.php
#	lib/firebase/php-jwt/src/JWT.php
This commit is contained in:
Molkobain
2023-02-23 16:27:50 +01:00
10 changed files with 242 additions and 127 deletions

View File

@@ -14,6 +14,7 @@
"ext-soap": "*", "ext-soap": "*",
"apereo/phpcas" : "~1.6.0", "apereo/phpcas" : "~1.6.0",
"combodo/tcpdf": "~6.4.4", "combodo/tcpdf": "~6.4.4",
"firebase/php-jwt": "~6.4.0",
"guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/guzzle": "^7.4.5",
"laminas/laminas-mail": "^2.11", "laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5", "laminas/laminas-servicemanager": "^3.5",

15
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "778cb837668f4ab5686021bf761d0a83", "content-hash": "69db9dbdea61a588fa2058724d91a579",
"packages": [ "packages": [
{ {
"name": "apereo/phpcas", "name": "apereo/phpcas",
@@ -154,16 +154,16 @@
}, },
{ {
"name": "firebase/php-jwt", "name": "firebase/php-jwt",
"version": "v6.3.0", "version": "v6.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/firebase/php-jwt.git", "url": "https://github.com/firebase/php-jwt.git",
"reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8" "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/018dfc4e1da92ad8a1b90adc4893f476a3b41cb8", "url": "https://api.github.com/repos/firebase/php-jwt/zipball/4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8", "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -178,6 +178,7 @@
"psr/http-factory": "^1.0" "psr/http-factory": "^1.0"
}, },
"suggest": { "suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
}, },
"type": "library", "type": "library",
@@ -210,9 +211,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/firebase/php-jwt/issues", "issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.3.0" "source": "https://github.com/firebase/php-jwt/tree/v6.4.0"
}, },
"time": "2022-07-15T16:48:45+00:00" "time": "2023-02-09T21:01:23+00:00"
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",

View File

@@ -154,17 +154,17 @@
}, },
{ {
"name": "firebase/php-jwt", "name": "firebase/php-jwt",
"version": "v6.3.0", "version": "v6.4.0",
"version_normalized": "6.3.0.0", "version_normalized": "6.4.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/firebase/php-jwt.git", "url": "https://github.com/firebase/php-jwt.git",
"reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8" "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/018dfc4e1da92ad8a1b90adc4893f476a3b41cb8", "url": "https://api.github.com/repos/firebase/php-jwt/zipball/4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8", "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -179,9 +179,10 @@
"psr/http-factory": "^1.0" "psr/http-factory": "^1.0"
}, },
"suggest": { "suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
}, },
"time": "2022-07-15T16:48:45+00:00", "time": "2023-02-09T21:01:23+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@@ -213,7 +214,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/firebase/php-jwt/issues", "issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.3.0" "source": "https://github.com/firebase/php-jwt/tree/v6.4.0"
}, },
"install-path": "../firebase/php-jwt" "install-path": "../firebase/php-jwt"
}, },

View File

@@ -5,7 +5,7 @@
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => 'd997e36de0f7ad4a820dbae8851c60f55fcd1c25', 'reference' => '4af0b9ab30a243b26bbebddcf190363ea6f28c83',
'name' => 'combodo/itop', 'name' => 'combodo/itop',
'dev' => true, 'dev' => true,
), ),
@@ -25,7 +25,7 @@
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => 'd997e36de0f7ad4a820dbae8851c60f55fcd1c25', 'reference' => '4af0b9ab30a243b26bbebddcf190363ea6f28c83',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'combodo/tcpdf' => array( 'combodo/tcpdf' => array(
@@ -44,12 +44,12 @@
), ),
), ),
'firebase/php-jwt' => array( 'firebase/php-jwt' => array(
'pretty_version' => 'v6.3.0', 'pretty_version' => 'v6.4.0',
'version' => '6.3.0.0', 'version' => '6.4.0.0',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt', 'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(), 'aliases' => array(),
'reference' => '018dfc4e1da92ad8a1b90adc4893f476a3b41cb8', 'reference' => '4dd1e007f22a927ac77da5a3fbb067b42d3bc224',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/guzzle' => array( 'guzzlehttp/guzzle' => array(

View File

@@ -0,0 +1,105 @@
# Changelog
## [6.4.0](https://github.com/firebase/php-jwt/compare/v6.3.2...v6.4.0) (2023-02-08)
### Features
* add support for W3C ES256K ([#462](https://github.com/firebase/php-jwt/issues/462)) ([213924f](https://github.com/firebase/php-jwt/commit/213924f51936291fbbca99158b11bd4ae56c2c95))
* improve caching by only decoding jwks when necessary ([#486](https://github.com/firebase/php-jwt/issues/486)) ([78d3ed1](https://github.com/firebase/php-jwt/commit/78d3ed1073553f7d0bbffa6c2010009a0d483d5c))
## [6.3.2](https://github.com/firebase/php-jwt/compare/v6.3.1...v6.3.2) (2022-11-01)
### Bug Fixes
* check kid before using as array index ([bad1b04](https://github.com/firebase/php-jwt/commit/bad1b040d0c736bbf86814c6b5ae614f517cf7bd))
## [6.3.1](https://github.com/firebase/php-jwt/compare/v6.3.0...v6.3.1) (2022-11-01)
### Bug Fixes
* casing of GET for PSR compat ([#451](https://github.com/firebase/php-jwt/issues/451)) ([60b52b7](https://github.com/firebase/php-jwt/commit/60b52b71978790eafcf3b95cfbd83db0439e8d22))
* string interpolation format for php 8.2 ([#446](https://github.com/firebase/php-jwt/issues/446)) ([2e07d8a](https://github.com/firebase/php-jwt/commit/2e07d8a1524d12b69b110ad649f17461d068b8f2))
## 6.3.0 / 2022-07-15
- Added ES256 support to JWK parsing ([#399](https://github.com/firebase/php-jwt/pull/399))
- Fixed potential caching error in `CachedKeySet` by caching jwks as strings ([#435](https://github.com/firebase/php-jwt/pull/435))
## 6.2.0 / 2022-05-14
- Added `CachedKeySet` ([#397](https://github.com/firebase/php-jwt/pull/397))
- Added `$defaultAlg` parameter to `JWT::parseKey` and `JWT::parseKeySet` ([#426](https://github.com/firebase/php-jwt/pull/426)).
## 6.1.0 / 2022-03-23
- Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0
- Add parameter typing and return types where possible
## 6.0.0 / 2022-01-24
- **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) 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)!
- Add an example for RS256 openssl.
See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)!
- Detect invalid Base64 encoding in signature.
See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)!
- Update `JWT::verify` to handle OpenSSL errors.
See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)!
- Add `array` type hinting to `decode` method
See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)!
- Add all JSON error types.
See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)!
- Bugfix 'kid' not in given key list.
See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)!
- Miscellaneous cleanup, documentation and test fixes.
See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115),
[#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and
[#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman),
[@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)!
## 4.0.0 / 2016-07-17
- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)!
- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)!
- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)!
- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)!
## 3.0.0 / 2015-07-22
- Minimum PHP version updated from `5.2.0` to `5.3.0`.
- Add `\Firebase\JWT` namespace. See
[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to
[@Dashron](https://github.com/Dashron)!
- Require a non-empty key to decode and verify a JWT. See
[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to
[@sjones608](https://github.com/sjones608)!
- Cleaner documentation blocks in the code. See
[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to
[@johanderuijter](https://github.com/johanderuijter)!
## 2.2.0 / 2015-06-22
- Add support for adding custom, optional JWT headers to `JWT::encode()`. See
[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to
[@mcocaro](https://github.com/mcocaro)!
## 2.1.0 / 2015-05-20
- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
- Add support for passing an object implementing the `ArrayAccess` interface for
`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
## 2.0.0 / 2015-04-01
- **Note**: It is strongly recommended that you update to > v2.0.0 to address
known security vulnerabilities in prior versions when both symmetric and
asymmetric keys are used together.
- Update signature for `JWT::decode(...)` to require an array of supported
algorithms to use when verifying token signatures.

View File

@@ -245,6 +245,56 @@ $decoded = JWT::decode($jwt, $keySet);
Miscellaneous Miscellaneous
------------- -------------
#### Exception Handling
When a call to `JWT::decode` is invalid, it will throw one of the following exceptions:
```php
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use DomainException;
use InvalidArgumentException;
use UnexpectedValueException;
try {
$decoded = JWT::decode($payload, $keys);
} catch (InvalidArgumentException $e) {
// provided key/key-array is empty or malformed.
} catch (DomainException $e) {
// provided algorithm is unsupported OR
// provided key is invalid OR
// unknown error thrown in openSSL or libsodium OR
// libsodium is required but not available.
} catch (SignatureInvalidException $e) {
// provided JWT signature verification failed.
} catch (BeforeValidException $e) {
// provided JWT is trying to be used before "nbf" claim OR
// provided JWT is trying to be used before "iat" claim.
} catch (ExpiredException $e) {
// provided JWT is trying to be used after "exp" claim.
} catch (UnexpectedValueException $e) {
// provided JWT is malformed OR
// provided JWT is missing an algorithm / using an unsupported algorithm OR
// provided JWT algorithm does not match provided key OR
// provided key ID in key/key-array is empty or invalid.
}
```
All exceptions in the `Firebase\JWT` namespace extend `UnexpectedValueException`, and can be simplified
like this:
```php
try {
$decoded = JWT::decode($payload, $keys);
} catch (LogicException $e) {
// errors having to do with environmental setup or malformed JWT Keys
} catch (UnexpectedValueException $e) {
// errors having to do with JWT signature and claims
}
```
#### Casting to array #### Casting to array
The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays
@@ -258,91 +308,6 @@ $decoded = JWT::decode($payload, $keys);
$decoded = json_decode(json_encode($decoded), true); $decoded = json_decode(json_encode($decoded), true);
``` ```
Changelog
---------
#### 6.3.0 / 2022-07-15
- Added ES256 support to JWK parsing ([#399](https://github.com/firebase/php-jwt/pull/399))
- Fixed potential caching error in `CachedKeySet` by caching jwks as strings ([#435](https://github.com/firebase/php-jwt/pull/435))
#### 6.2.0 / 2022-05-14
- Added `CachedKeySet` ([#397](https://github.com/firebase/php-jwt/pull/397))
- Added `$defaultAlg` parameter to `JWT::parseKey` and `JWT::parseKeySet` ([#426](https://github.com/firebase/php-jwt/pull/426)).
#### 6.1.0 / 2022-03-23
- Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0
- Add parameter typing and return types where possible
#### 6.0.0 / 2022-01-24
- **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) 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)!
- Add an example for RS256 openssl.
See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)!
- Detect invalid Base64 encoding in signature.
See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)!
- Update `JWT::verify` to handle OpenSSL errors.
See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)!
- Add `array` type hinting to `decode` method
See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)!
- Add all JSON error types.
See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)!
- Bugfix 'kid' not in given key list.
See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)!
- Miscellaneous cleanup, documentation and test fixes.
See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115),
[#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and
[#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman),
[@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)!
#### 4.0.0 / 2016-07-17
- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)!
- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)!
- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)!
- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)!
#### 3.0.0 / 2015-07-22
- Minimum PHP version updated from `5.2.0` to `5.3.0`.
- Add `\Firebase\JWT` namespace. See
[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to
[@Dashron](https://github.com/Dashron)!
- Require a non-empty key to decode and verify a JWT. See
[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to
[@sjones608](https://github.com/sjones608)!
- Cleaner documentation blocks in the code. See
[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to
[@johanderuijter](https://github.com/johanderuijter)!
#### 2.2.0 / 2015-06-22
- Add support for adding custom, optional JWT headers to `JWT::encode()`. See
[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to
[@mcocaro](https://github.com/mcocaro)!
#### 2.1.0 / 2015-05-20
- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
- Add support for passing an object implementing the `ArrayAccess` interface for
`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
#### 2.0.0 / 2015-04-01
- **Note**: It is strongly recommended that you update to > v2.0.0 to address
known security vulnerabilities in prior versions when both symmetric and
asymmetric keys are used together.
- Update signature for `JWT::decode(...)` to require an array of supported
algorithms to use when verifying token signatures.
Tests Tests
----- -----
Run the tests using phpunit: Run the tests using phpunit:

View File

@@ -23,7 +23,8 @@
"php": "^7.1||^8.0" "php": "^7.1||^8.0"
}, },
"suggest": { "suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
"ext-sodium": "Support EdDSA (Ed25519) signatures"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View File

@@ -3,6 +3,7 @@
namespace Firebase\JWT; namespace Firebase\JWT;
use ArrayAccess; use ArrayAccess;
use InvalidArgumentException;
use LogicException; use LogicException;
use OutOfBoundsException; use OutOfBoundsException;
use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemInterface;
@@ -10,6 +11,7 @@ use Psr\Cache\CacheItemPoolInterface;
use Psr\Http\Client\ClientInterface; use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestFactoryInterface;
use RuntimeException; use RuntimeException;
use UnexpectedValueException;
/** /**
* @implements ArrayAccess<string, Key> * @implements ArrayAccess<string, Key>
@@ -41,7 +43,7 @@ class CachedKeySet implements ArrayAccess
*/ */
private $cacheItem; private $cacheItem;
/** /**
* @var array<string, Key> * @var array<string, array<mixed>>
*/ */
private $keySet; private $keySet;
/** /**
@@ -101,7 +103,7 @@ class CachedKeySet implements ArrayAccess
if (!$this->keyIdExists($keyId)) { if (!$this->keyIdExists($keyId)) {
throw new OutOfBoundsException('Key ID not found'); throw new OutOfBoundsException('Key ID not found');
} }
return $this->keySet[$keyId]; return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
} }
/** /**
@@ -130,15 +132,43 @@ class CachedKeySet implements ArrayAccess
throw new LogicException('Method not implemented'); throw new LogicException('Method not implemented');
} }
/**
* @return array<mixed>
*/
private function formatJwksForCache(string $jwks): array
{
$jwks = json_decode($jwks, true);
if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
}
if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
}
$keys = [];
foreach ($jwks['keys'] as $k => $v) {
$kid = isset($v['kid']) ? $v['kid'] : $k;
$keys[(string) $kid] = $v;
}
return $keys;
}
private function keyIdExists(string $keyId): bool private function keyIdExists(string $keyId): bool
{ {
if (null === $this->keySet) { if (null === $this->keySet) {
$item = $this->getCacheItem(); $item = $this->getCacheItem();
// Try to load keys from cache // Try to load keys from cache
if ($item->isHit()) { if ($item->isHit()) {
// item found! Return it // item found! retrieve it
$jwks = $item->get(); $this->keySet = $item->get();
$this->keySet = JWK::parseKeySet(json_decode($jwks, true), $this->defaultAlg); // If the cached item is a string, the JWKS response was cached (previous behavior).
// Parse this into expected format array<kid, jwk> instead.
if (\is_string($this->keySet)) {
$this->keySet = $this->formatJwksForCache($this->keySet);
}
} }
} }
@@ -146,17 +176,16 @@ class CachedKeySet implements ArrayAccess
if ($this->rateLimitExceeded()) { if ($this->rateLimitExceeded()) {
return false; return false;
} }
$request = $this->httpFactory->createRequest('get', $this->jwksUri); $request = $this->httpFactory->createRequest('GET', $this->jwksUri);
$jwksResponse = $this->httpClient->sendRequest($request); $jwksResponse = $this->httpClient->sendRequest($request);
$jwks = (string) $jwksResponse->getBody(); $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
$this->keySet = JWK::parseKeySet(json_decode($jwks, true), $this->defaultAlg);
if (!isset($this->keySet[$keyId])) { if (!isset($this->keySet[$keyId])) {
return false; return false;
} }
$item = $this->getCacheItem(); $item = $this->getCacheItem();
$item->set($jwks); $item->set($this->keySet);
if ($this->expiresAfter) { if ($this->expiresAfter) {
$item->expiresAfter($this->expiresAfter); $item->expiresAfter($this->expiresAfter);
} }

View File

@@ -26,6 +26,7 @@ class JWK
private const ASN1_BIT_STRING = 0x03; private const ASN1_BIT_STRING = 0x03;
private const EC_CURVES = [ private const EC_CURVES = [
'P-256' => '1.2.840.10045.3.1.7', // Len: 64 'P-256' => '1.2.840.10045.3.1.7', // Len: 64
'secp256k1' => '1.3.132.0.10', // Len: 64
// 'P-384' => '1.3.132.0.34', // Len: 96 (not yet supported) // 'P-384' => '1.3.132.0.34', // Len: 96 (not yet supported)
// 'P-521' => '1.3.132.0.35', // Len: 132 (not supported) // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
]; ];

View File

@@ -55,6 +55,7 @@ class JWT
public static $supported_algs = [ public static $supported_algs = [
'ES384' => ['openssl', 'SHA384'], 'ES384' => ['openssl', 'SHA384'],
'ES256' => ['openssl', 'SHA256'], 'ES256' => ['openssl', 'SHA256'],
'ES256K' => ['openssl', 'SHA256'],
'HS256' => ['hash_hmac', 'SHA256'], 'HS256' => ['hash_hmac', 'SHA256'],
'HS384' => ['hash_hmac', 'SHA384'], 'HS384' => ['hash_hmac', 'SHA384'],
'HS512' => ['hash_hmac', 'SHA512'], 'HS512' => ['hash_hmac', 'SHA512'],
@@ -76,7 +77,7 @@ class JWT
* *
* @return stdClass The JWT's payload as a PHP object * @return stdClass The JWT's payload as a PHP object
* *
* @throws InvalidArgumentException Provided key/key-array was empty * @throws InvalidArgumentException Provided key/key-array was empty or malformed
* @throws DomainException Provided JWT is malformed * @throws DomainException Provided JWT is malformed
* @throws UnexpectedValueException Provided JWT was invalid * @throws UnexpectedValueException Provided JWT was invalid
* @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
@@ -132,11 +133,11 @@ class JWT
// See issue #351 // See issue #351
throw new UnexpectedValueException('Incorrect key for this algorithm'); throw new UnexpectedValueException('Incorrect key for this algorithm');
} }
if ($header->alg === 'ES256' || $header->alg === 'ES384') { if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) {
// OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures
$sig = self::signatureToDER($sig); $sig = self::signatureToDER($sig);
} }
if (!self::verify("${headb64}.${bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) { if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) {
throw new SignatureInvalidException('Signature verification failed'); throw new SignatureInvalidException('Signature verification failed');
} }
@@ -166,12 +167,12 @@ class JWT
} }
/** /**
* Converts and signs a PHP object or array into a JWT string. * Converts and signs a PHP array into a JWT string.
* *
* @param array<mixed> $payload PHP array * @param array<mixed> $payload PHP array
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'HS256', 'HS384', * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* 'HS512', 'RS256', 'RS384', and 'RS512' * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* @param string $keyId * @param string $keyId
* @param array<string, string> $head An array with header elements to attach * @param array<string, string> $head An array with header elements to attach
* *
@@ -210,8 +211,8 @@ class JWT
* *
* @param string $msg The message to sign * @param string $msg The message to sign
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'HS256', 'HS384', * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* 'HS512', 'RS256', 'RS384', and 'RS512' * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* *
* @return string An encrypted message * @return string An encrypted message
* *
@@ -238,7 +239,7 @@ class JWT
if (!$success) { if (!$success) {
throw new DomainException('OpenSSL unable to sign data'); throw new DomainException('OpenSSL unable to sign data');
} }
if ($alg === 'ES256') { if ($alg === 'ES256' || $alg === 'ES256K') {
$signature = self::signatureFromDER($signature, 256); $signature = self::signatureFromDER($signature, 256);
} elseif ($alg === 'ES384') { } elseif ($alg === 'ES384') {
$signature = self::signatureFromDER($signature, 384); $signature = self::signatureFromDER($signature, 384);
@@ -255,6 +256,9 @@ class JWT
// The last non-empty line is used as the key. // The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $key)); $lines = array_filter(explode("\n", $key));
$key = base64_decode((string) end($lines)); $key = base64_decode((string) end($lines));
if (\strlen($key) === 0) {
throw new DomainException('Key cannot be empty string');
}
return sodium_crypto_sign_detached($msg, $key); return sodium_crypto_sign_detached($msg, $key);
} catch (Exception $e) { } catch (Exception $e) {
throw new DomainException($e->getMessage(), 0, $e); throw new DomainException($e->getMessage(), 0, $e);
@@ -312,6 +316,12 @@ class JWT
// The last non-empty line is used as the key. // The last non-empty line is used as the key.
$lines = array_filter(explode("\n", $keyMaterial)); $lines = array_filter(explode("\n", $keyMaterial));
$key = base64_decode((string) end($lines)); $key = base64_decode((string) end($lines));
if (\strlen($key) === 0) {
throw new DomainException('Key cannot be empty string');
}
if (\strlen($signature) === 0) {
throw new DomainException('Signature cannot be empty string');
}
return sodium_crypto_sign_verify_detached($signature, $msg, $key); return sodium_crypto_sign_verify_detached($signature, $msg, $key);
} catch (Exception $e) { } catch (Exception $e) {
throw new DomainException($e->getMessage(), 0, $e); throw new DomainException($e->getMessage(), 0, $e);
@@ -425,14 +435,15 @@ class JWT
return $keyOrKeyArray; return $keyOrKeyArray;
} }
if (empty($kid)) {
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}
if ($keyOrKeyArray instanceof CachedKeySet) { if ($keyOrKeyArray instanceof CachedKeySet) {
// Skip "isset" check, as this will automatically refresh if not set // Skip "isset" check, as this will automatically refresh if not set
return $keyOrKeyArray[$kid]; return $keyOrKeyArray[$kid];
} }
if (empty($kid)) {
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
}
if (!isset($keyOrKeyArray[$kid])) { if (!isset($keyOrKeyArray[$kid])) {
throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key'); throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
} }