Browse Source

[Web] update stevenmaguire/oauth2-keycloak and firebase/php-jwt

FreddleSpl0it 2 years ago
parent
commit
cee771a3fb

+ 1 - 1
data/web/inc/lib/composer.json

@@ -10,7 +10,7 @@
         "mustangostang/spyc": "^0.6.3",
         "directorytree/ldaprecord": "^2.4",
         "twig/twig": "^3.0",
-        "stevenmaguire/oauth2-keycloak": "^3.2",
+        "stevenmaguire/oauth2-keycloak": "^4.0",
         "league/oauth2-client": "^2.7"
     }
 }

+ 27 - 20
data/web/inc/lib/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "ee35a2bf8c80a87b6825c3e86635f709",
+    "content-hash": "8f5a147cdb147b935a158b86f47a4747",
     "packages": [
         {
             "name": "bshaffer/oauth2-server-php",
@@ -218,25 +218,31 @@
         },
         {
             "name": "firebase/php-jwt",
-            "version": "v5.5.1",
+            "version": "v6.5.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/firebase/php-jwt.git",
-                "reference": "83b609028194aa042ea33b5af2d41a7427de80e6"
+                "reference": "e94e7353302b0c11ec3cfff7180cd0b1743975d2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6",
-                "reference": "83b609028194aa042ea33b5af2d41a7427de80e6",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/e94e7353302b0c11ec3cfff7180cd0b1743975d2",
+                "reference": "e94e7353302b0c11ec3cfff7180cd0b1743975d2",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "php": "^7.4||^8.0"
             },
             "require-dev": {
-                "phpunit/phpunit": ">=4.8 <=9"
+                "guzzlehttp/guzzle": "^6.5||^7.4",
+                "phpspec/prophecy-phpunit": "^2.0",
+                "phpunit/phpunit": "^9.5",
+                "psr/cache": "^1.0||^2.0",
+                "psr/http-client": "^1.0",
+                "psr/http-factory": "^1.0"
             },
             "suggest": {
+                "ext-sodium": "Support EdDSA (Ed25519) signatures",
                 "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
             },
             "type": "library",
@@ -269,9 +275,9 @@
             ],
             "support": {
                 "issues": "https://github.com/firebase/php-jwt/issues",
-                "source": "https://github.com/firebase/php-jwt/tree/v5.5.1"
+                "source": "https://github.com/firebase/php-jwt/tree/v6.5.0"
             },
-            "time": "2021-11-08T20:18:51+00:00"
+            "time": "2023-05-12T15:47:07+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
@@ -1703,26 +1709,27 @@
         },
         {
             "name": "stevenmaguire/oauth2-keycloak",
-            "version": "3.2.0",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/stevenmaguire/oauth2-keycloak.git",
-                "reference": "34e4824f5fa26aa8e90f1258859c75570c12d27a"
+                "reference": "05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/stevenmaguire/oauth2-keycloak/zipball/34e4824f5fa26aa8e90f1258859c75570c12d27a",
-                "reference": "34e4824f5fa26aa8e90f1258859c75570c12d27a",
+                "url": "https://api.github.com/repos/stevenmaguire/oauth2-keycloak/zipball/05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d",
+                "reference": "05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d",
                 "shasum": ""
             },
             "require": {
-                "firebase/php-jwt": "~4.0|~5.0",
-                "league/oauth2-client": "^2.0"
+                "firebase/php-jwt": "^4.0 || ^5.0 || ^6.0",
+                "league/oauth2-client": "^2.0",
+                "php": "~7.2 || ~8.0"
             },
             "require-dev": {
-                "mockery/mockery": "~0.9",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
+                "mockery/mockery": "~1.5.0",
+                "phpunit/phpunit": "~9.6.4",
+                "squizlabs/php_codesniffer": "~3.7.0"
             },
             "type": "library",
             "extra": {
@@ -1757,9 +1764,9 @@
             ],
             "support": {
                 "issues": "https://github.com/stevenmaguire/oauth2-keycloak/issues",
-                "source": "https://github.com/stevenmaguire/oauth2-keycloak/tree/3.2.0"
+                "source": "https://github.com/stevenmaguire/oauth2-keycloak/tree/4.0.0"
             },
-            "time": "2022-12-16T12:46:38+00:00"
+            "time": "2023-03-14T09:43:47+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",

+ 28 - 21
data/web/inc/lib/vendor/composer/installed.json

@@ -217,29 +217,35 @@
         },
         {
             "name": "firebase/php-jwt",
-            "version": "v5.5.1",
-            "version_normalized": "5.5.1.0",
+            "version": "v6.5.0",
+            "version_normalized": "6.5.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/firebase/php-jwt.git",
-                "reference": "83b609028194aa042ea33b5af2d41a7427de80e6"
+                "reference": "e94e7353302b0c11ec3cfff7180cd0b1743975d2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6",
-                "reference": "83b609028194aa042ea33b5af2d41a7427de80e6",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/e94e7353302b0c11ec3cfff7180cd0b1743975d2",
+                "reference": "e94e7353302b0c11ec3cfff7180cd0b1743975d2",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "php": "^7.4||^8.0"
             },
             "require-dev": {
-                "phpunit/phpunit": ">=4.8 <=9"
+                "guzzlehttp/guzzle": "^6.5||^7.4",
+                "phpspec/prophecy-phpunit": "^2.0",
+                "phpunit/phpunit": "^9.5",
+                "psr/cache": "^1.0||^2.0",
+                "psr/http-client": "^1.0",
+                "psr/http-factory": "^1.0"
             },
             "suggest": {
+                "ext-sodium": "Support EdDSA (Ed25519) signatures",
                 "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
             },
-            "time": "2021-11-08T20:18:51+00:00",
+            "time": "2023-05-12T15:47:07+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -271,7 +277,7 @@
             ],
             "support": {
                 "issues": "https://github.com/firebase/php-jwt/issues",
-                "source": "https://github.com/firebase/php-jwt/tree/v5.5.1"
+                "source": "https://github.com/firebase/php-jwt/tree/v6.5.0"
             },
             "install-path": "../firebase/php-jwt"
         },
@@ -1759,29 +1765,30 @@
         },
         {
             "name": "stevenmaguire/oauth2-keycloak",
-            "version": "3.2.0",
-            "version_normalized": "3.2.0.0",
+            "version": "4.0.0",
+            "version_normalized": "4.0.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/stevenmaguire/oauth2-keycloak.git",
-                "reference": "34e4824f5fa26aa8e90f1258859c75570c12d27a"
+                "reference": "05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/stevenmaguire/oauth2-keycloak/zipball/34e4824f5fa26aa8e90f1258859c75570c12d27a",
-                "reference": "34e4824f5fa26aa8e90f1258859c75570c12d27a",
+                "url": "https://api.github.com/repos/stevenmaguire/oauth2-keycloak/zipball/05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d",
+                "reference": "05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d",
                 "shasum": ""
             },
             "require": {
-                "firebase/php-jwt": "~4.0|~5.0",
-                "league/oauth2-client": "^2.0"
+                "firebase/php-jwt": "^4.0 || ^5.0 || ^6.0",
+                "league/oauth2-client": "^2.0",
+                "php": "~7.2 || ~8.0"
             },
             "require-dev": {
-                "mockery/mockery": "~0.9",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
+                "mockery/mockery": "~1.5.0",
+                "phpunit/phpunit": "~9.6.4",
+                "squizlabs/php_codesniffer": "~3.7.0"
             },
-            "time": "2022-12-16T12:46:38+00:00",
+            "time": "2023-03-14T09:43:47+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
@@ -1816,7 +1823,7 @@
             ],
             "support": {
                 "issues": "https://github.com/stevenmaguire/oauth2-keycloak/issues",
-                "source": "https://github.com/stevenmaguire/oauth2-keycloak/tree/3.2.0"
+                "source": "https://github.com/stevenmaguire/oauth2-keycloak/tree/4.0.0"
             },
             "install-path": "../stevenmaguire/oauth2-keycloak"
         },

+ 8 - 8
data/web/inc/lib/vendor/composer/installed.php

@@ -3,7 +3,7 @@
         'name' => '__root__',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '07edec4ea50b8eedae10c28eba0b4b2774df537e',
+        'reference' => '34e7b3f613661fe2b3c3eb1d316a63dfe111022e',
         'type' => 'library',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -13,7 +13,7 @@
         '__root__' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '07edec4ea50b8eedae10c28eba0b4b2774df537e',
+            'reference' => '34e7b3f613661fe2b3c3eb1d316a63dfe111022e',
             'type' => 'library',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -53,9 +53,9 @@
             ),
         ),
         'firebase/php-jwt' => array(
-            'pretty_version' => 'v5.5.1',
-            'version' => '5.5.1.0',
-            'reference' => '83b609028194aa042ea33b5af2d41a7427de80e6',
+            'pretty_version' => 'v6.5.0',
+            'version' => '6.5.0.0',
+            'reference' => 'e94e7353302b0c11ec3cfff7180cd0b1743975d2',
             'type' => 'library',
             'install_path' => __DIR__ . '/../firebase/php-jwt',
             'aliases' => array(),
@@ -275,9 +275,9 @@
             'dev_requirement' => false,
         ),
         'stevenmaguire/oauth2-keycloak' => array(
-            'pretty_version' => '3.2.0',
-            'version' => '3.2.0.0',
-            'reference' => '34e4824f5fa26aa8e90f1258859c75570c12d27a',
+            'pretty_version' => '4.0.0',
+            'version' => '4.0.0.0',
+            'reference' => '05ead6bb6bcd2b6f96dfae87c769dcd3e5f6129d',
             'type' => 'library',
             'install_path' => __DIR__ . '/../stevenmaguire/oauth2-keycloak',
             'aliases' => array(),

+ 117 - 0
data/web/inc/lib/vendor/firebase/php-jwt/CHANGELOG.md

@@ -0,0 +1,117 @@
+# Changelog
+
+## [6.5.0](https://github.com/firebase/php-jwt/compare/v6.4.0...v6.5.0) (2023-05-12)
+
+
+### Bug Fixes
+
+* allow KID of '0' ([#505](https://github.com/firebase/php-jwt/issues/505)) ([9dc46a9](https://github.com/firebase/php-jwt/commit/9dc46a9c3e5801294249cfd2554c5363c9f9326a))
+
+
+### Miscellaneous Chores
+
+* drop support for PHP 7.3 ([#495](https://github.com/firebase/php-jwt/issues/495))
+
+## [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.

+ 236 - 106
data/web/inc/lib/vendor/firebase/php-jwt/README.md

@@ -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)
@@ -29,13 +29,13 @@ Example
 use Firebase\JWT\JWT;
 use Firebase\JWT\Key;
 
-$key = "example_key";
-$payload = array(
-    "iss" => "http://example.org",
-    "aud" => "http://example.com",
-    "iat" => 1356999524,
-    "nbf" => 1357000000
-);
+$key = 'example_key';
+$payload = [
+    'iss' => 'http://example.org',
+    'aud' => 'http://example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
 
 /**
  * IMPORTANT:
@@ -65,6 +65,40 @@ $decoded_array = (array) $decoded;
 JWT::$leeway = 60; // $leeway in seconds
 $decoded = JWT::decode($jwt, new Key($key, 'HS256'));
 ```
+Example encode/decode headers
+-------
+Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by
+this library. This is because without verifying the JWT, the header values could have been tampered with.
+Any value pulled from an unverified header should be treated as if it could be any string sent in from an
+attacker.  If this is something you still want to do in your application for whatever reason, it's possible to 
+decode the header values manually simply by calling `json_decode` and `base64_decode` on the JWT 
+header part:
+```php
+use Firebase\JWT\JWT;
+
+$key = 'example_key';
+$payload = [
+    'iss' => 'http://example.org',
+    'aud' => 'http://example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
+
+$headers = [
+    'x-forwarded-for' => 'www.google.com'
+];
+
+// Encode headers in the JWT string
+$jwt = JWT::encode($payload, $key, 'HS256', null, $headers);
+
+// Decode headers from the JWT string WITHOUT validation
+// **IMPORTANT**: This operation is vulnerable to attacks, as the JWT has not yet been verified.
+// These headers could be any value sent by an attacker.
+list($headersB64, $payloadB64, $sig) = explode('.', $jwt);
+$decoded = json_decode(base64_decode($headersB64), true);
+
+print_r($decoded);
+```
 Example with RS256 (openssl)
 ----------------------------
 ```php
@@ -73,37 +107,52 @@ use Firebase\JWT\Key;
 
 $privateKey = <<<EOD
 -----BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQC8kGa1pSjbSYZVebtTRBLxBz5H4i2p/llLCrEeQhta5kaQu/Rn
-vuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t0tyazyZ8JXw+KgXTxldMPEL9
-5+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4ehde/zUxo6UvS7UrBQIDAQAB
-AoGAb/MXV46XxCFRxNuB8LyAtmLDgi/xRnTAlMHjSACddwkyKem8//8eZtw9fzxz
-bWZ/1/doQOuHBGYZU8aDzzj59FZ78dyzNFoF91hbvZKkg+6wGyd/LrGVEB+Xre0J
-Nil0GReM2AHDNZUYRv+HYJPIOrB0CRczLQsgFJ8K6aAD6F0CQQDzbpjYdx10qgK1
-cP59UHiHjPZYC0loEsk7s+hUmT3QHerAQJMZWC11Qrn2N+ybwwNblDKv+s5qgMQ5
-5tNoQ9IfAkEAxkyffU6ythpg/H0Ixe1I2rd0GbF05biIzO/i77Det3n4YsJVlDck
-ZkcvY3SK2iRIL4c9yY6hlIhs+K9wXTtGWwJBAO9Dskl48mO7woPR9uD22jDpNSwe
-k90OMepTjzSvlhjbfuPN1IdhqvSJTDychRwn1kIJ7LQZgQ8fVz9OCFZ/6qMCQGOb
-qaGwHmUK6xzpUbbacnYrIM6nLSkXgOAwv7XXCojvY614ILTK3iXiLBOxPu5Eu13k
-eUz9sHyD6vkgZzjtxXECQAkp4Xerf5TGfQXGXhxIX52yH+N2LtujCdkQZjXAsGdm
-B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM=
+MIIEowIBAAKCAQEAuzWHNM5f+amCjQztc5QTfJfzCC5J4nuW+L/aOxZ4f8J3Frew
+M2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJhzkPYLae7bTVro3hok0zDITR8F6S
+JGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548tu4czCuqU8BGVOlnp6IqBHhAswNMM
+78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vSopcT51koWOgiTf3C7nJUoMWZHZI5
+HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTzTTqo1SCSH2pooJl9O8at6kkRYsrZ
+WwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/BwQIDAQABAoIBAFtGaOqNKGwggn9k
+6yzr6GhZ6Wt2rh1Xpq8XUz514UBhPxD7dFRLpbzCrLVpzY80LbmVGJ9+1pJozyWc
+VKeCeUdNwbqkr240Oe7GTFmGjDoxU+5/HX/SJYPpC8JZ9oqgEA87iz+WQX9hVoP2
+oF6EB4ckDvXmk8FMwVZW2l2/kd5mrEVbDaXKxhvUDf52iVD+sGIlTif7mBgR99/b
+c3qiCnxCMmfYUnT2eh7Vv2LhCR/G9S6C3R4lA71rEyiU3KgsGfg0d82/XWXbegJW
+h3QbWNtQLxTuIvLq5aAryV3PfaHlPgdgK0ft6ocU2de2FagFka3nfVEyC7IUsNTK
+bq6nhAECgYEA7d/0DPOIaItl/8BWKyCuAHMss47j0wlGbBSHdJIiS55akMvnAG0M
+39y22Qqfzh1at9kBFeYeFIIU82ZLF3xOcE3z6pJZ4Dyvx4BYdXH77odo9uVK9s1l
+3T3BlMcqd1hvZLMS7dviyH79jZo4CXSHiKzc7pQ2YfK5eKxKqONeXuECgYEAyXlG
+vonaus/YTb1IBei9HwaccnQ/1HRn6MvfDjb7JJDIBhNClGPt6xRlzBbSZ73c2QEC
+6Fu9h36K/HZ2qcLd2bXiNyhIV7b6tVKk+0Psoj0dL9EbhsD1OsmE1nTPyAc9XZbb
+OPYxy+dpBCUA8/1U9+uiFoCa7mIbWcSQ+39gHuECgYAz82pQfct30aH4JiBrkNqP
+nJfRq05UY70uk5k1u0ikLTRoVS/hJu/d4E1Kv4hBMqYCavFSwAwnvHUo51lVCr/y
+xQOVYlsgnwBg2MX4+GjmIkqpSVCC8D7j/73MaWb746OIYZervQ8dbKahi2HbpsiG
+8AHcVSA/agxZr38qvWV54QKBgCD5TlDE8x18AuTGQ9FjxAAd7uD0kbXNz2vUYg9L
+hFL5tyL3aAAtUrUUw4xhd9IuysRhW/53dU+FsG2dXdJu6CxHjlyEpUJl2iZu/j15
+YnMzGWHIEX8+eWRDsw/+Ujtko/B7TinGcWPz3cYl4EAOiCeDUyXnqnO1btCEUU44
+DJ1BAoGBAJuPD27ErTSVtId90+M4zFPNibFP50KprVdc8CR37BE7r8vuGgNYXmnI
+RLnGP9p3pVgFCktORuYS2J/6t84I3+A17nEoB4xvhTLeAinAW/uTQOUmNicOP4Ek
+2MsLL2kHgL8bLTmvXV4FX+PXphrDKg1XxzOYn0otuoqdAQrkK4og
 -----END RSA PRIVATE KEY-----
 EOD;
 
 $publicKey = <<<EOD
 -----BEGIN PUBLIC KEY-----
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kGa1pSjbSYZVebtTRBLxBz5H
-4i2p/llLCrEeQhta5kaQu/RnvuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t
-0tyazyZ8JXw+KgXTxldMPEL95+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4
-ehde/zUxo6UvS7UrBQIDAQAB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzWHNM5f+amCjQztc5QT
+fJfzCC5J4nuW+L/aOxZ4f8J3FrewM2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJ
+hzkPYLae7bTVro3hok0zDITR8F6SJGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548t
+u4czCuqU8BGVOlnp6IqBHhAswNMM78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vS
+opcT51koWOgiTf3C7nJUoMWZHZI5HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTz
+TTqo1SCSH2pooJl9O8at6kkRYsrZWwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/B
+wQIDAQAB
 -----END PUBLIC KEY-----
 EOD;
 
-$payload = array(
-    "iss" => "example.org",
-    "aud" => "example.com",
-    "iat" => 1356999524,
-    "nbf" => 1357000000
-);
+$payload = [
+    'iss' => 'example.org',
+    'aud' => 'example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
 
 $jwt = JWT::encode($payload, $privateKey, 'RS256');
 echo "Encode:\n" . print_r($jwt, true) . "\n";
@@ -139,12 +188,12 @@ $privateKey = openssl_pkey_get_private(
     $passphrase
 );
 
-$payload = array(
-    "iss" => "example.org",
-    "aud" => "example.com",
-    "iat" => 1356999524,
-    "nbf" => 1357000000
-);
+$payload = [
+    'iss' => 'example.org',
+    'aud' => 'example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
 
 $jwt = JWT::encode($payload, $privateKey, 'RS256');
 echo "Encode:\n" . print_r($jwt, true) . "\n";
@@ -173,12 +222,12 @@ $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
-);
+$payload = [
+    'iss' => 'example.org',
+    'aud' => 'example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
 
 $jwt = JWT::encode($payload, $privateKey, 'EdDSA');
 echo "Encode:\n" . print_r($jwt, true) . "\n";
@@ -187,6 +236,44 @@ $decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
 echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
 ````
 
+Example with multiple keys
+--------------------------
+```php
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+
+// Example RSA keys from previous example
+// $privateKey1 = '...';
+// $publicKey1 = '...';
+
+// Example EdDSA keys from previous example
+// $privateKey2 = '...';
+// $publicKey2 = '...';
+
+$payload = [
+    'iss' => 'example.org',
+    'aud' => 'example.com',
+    'iat' => 1356999524,
+    'nbf' => 1357000000
+];
+
+$jwt1 = JWT::encode($payload, $privateKey1, 'RS256', 'kid1');
+$jwt2 = JWT::encode($payload, $privateKey2, 'EdDSA', 'kid2');
+echo "Encode 1:\n" . print_r($jwt1, true) . "\n";
+echo "Encode 2:\n" . print_r($jwt2, true) . "\n";
+
+$keys = [
+    'kid1' => new Key($publicKey1, 'RS256'),
+    'kid2' => new Key($publicKey2, 'EdDSA'),
+];
+
+$decoded1 = JWT::decode($jwt1, $keys);
+$decoded2 = JWT::decode($jwt2, $keys);
+
+echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n";
+echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n";
+```
+
 Using JWKs
 ----------
 
@@ -198,72 +285,115 @@ use Firebase\JWT\JWT;
 // this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
 $jwks = ['keys' => []];
 
-// JWK::parseKeySet($jwks) returns an associative array of **kid** to private
-// key. Pass this as the second parameter to JWT::decode.
-// NOTE: The deprecated $supportedAlgorithm must be supplied when parsing from JWK.
-JWT::decode($payload, JWK::parseKeySet($jwks), $supportedAlgorithm);
+// 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
----------
-
-#### 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.
+Using Cached Key Sets
+---------------------
+
+The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI.
+This has the following advantages:
+
+1. The results are cached for performance.
+2. If an unrecognized key is requested, the cache is refreshed, to accomodate for key rotation.
+3. If rate limiting is enabled, the JWKS URI will not make more than 10 requests a second.
 
+```php
+use Firebase\JWT\CachedKeySet;
+use Firebase\JWT\JWT;
+
+// The URI for the JWKS you wish to cache the results from
+$jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk';
+
+// Create an HTTP client (can be any PSR-7 compatible HTTP client)
+$httpClient = new GuzzleHttp\Client();
+
+// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory)
+$httpFactory = new GuzzleHttp\Psr\HttpFactory();
+
+// Create a cache item pool (can be any PSR-6 compatible cache item pool)
+$cacheItemPool = Phpfastcache\CacheManager::getInstance('files');
+
+$keySet = new CachedKeySet(
+    $jwksUri,
+    $httpClient,
+    $httpFactory,
+    $cacheItemPool,
+    null, // $expiresAfter int seconds to set the JWKS to expire
+    true  // $rateLimit    true to enable rate limit of 10 RPS on lookup of invalid keys
+);
+
+$jwt = 'eyJhbGci...'; // Some JWT signed by a key from the $jwkUri above
+$decoded = JWT::decode($jwt, $keySet);
+```
+
+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
+
+The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays
+instead, you can do the following:
+
+```php
+// return type is stdClass
+$decoded = JWT::decode($payload, $keys);
+
+// cast to array
+$decoded = json_decode(json_encode($decoded), true);
+```
 
 Tests
 -----

+ 9 - 3
data/web/inc/lib/vendor/firebase/php-jwt/composer.json

@@ -20,10 +20,11 @@
     ],
     "license": "BSD-3-Clause",
     "require": {
-        "php": ">=5.3.0"
+        "php": "^7.4||^8.0"
     },
     "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": {
         "psr-4": {
@@ -31,6 +32,11 @@
         }
     },
     "require-dev": {
-        "phpunit/phpunit": ">=4.8 <=9"
+        "guzzlehttp/guzzle": "^6.5||^7.4",
+        "phpspec/prophecy-phpunit": "^2.0",
+        "phpunit/phpunit": "^9.5",
+        "psr/cache": "^1.0||^2.0",
+        "psr/http-client": "^1.0",
+        "psr/http-factory": "^1.0"
     }
 }

+ 258 - 0
data/web/inc/lib/vendor/firebase/php-jwt/src/CachedKeySet.php

@@ -0,0 +1,258 @@
+<?php
+
+namespace Firebase\JWT;
+
+use ArrayAccess;
+use InvalidArgumentException;
+use LogicException;
+use OutOfBoundsException;
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\Http\Client\ClientInterface;
+use Psr\Http\Message\RequestFactoryInterface;
+use RuntimeException;
+use UnexpectedValueException;
+
+/**
+ * @implements ArrayAccess<string, Key>
+ */
+class CachedKeySet implements ArrayAccess
+{
+    /**
+     * @var string
+     */
+    private $jwksUri;
+    /**
+     * @var ClientInterface
+     */
+    private $httpClient;
+    /**
+     * @var RequestFactoryInterface
+     */
+    private $httpFactory;
+    /**
+     * @var CacheItemPoolInterface
+     */
+    private $cache;
+    /**
+     * @var ?int
+     */
+    private $expiresAfter;
+    /**
+     * @var ?CacheItemInterface
+     */
+    private $cacheItem;
+    /**
+     * @var array<string, array<mixed>>
+     */
+    private $keySet;
+    /**
+     * @var string
+     */
+    private $cacheKey;
+    /**
+     * @var string
+     */
+    private $cacheKeyPrefix = 'jwks';
+    /**
+     * @var int
+     */
+    private $maxKeyLength = 64;
+    /**
+     * @var bool
+     */
+    private $rateLimit;
+    /**
+     * @var string
+     */
+    private $rateLimitCacheKey;
+    /**
+     * @var int
+     */
+    private $maxCallsPerMinute = 10;
+    /**
+     * @var string|null
+     */
+    private $defaultAlg;
+
+    public function __construct(
+        string $jwksUri,
+        ClientInterface $httpClient,
+        RequestFactoryInterface $httpFactory,
+        CacheItemPoolInterface $cache,
+        int $expiresAfter = null,
+        bool $rateLimit = false,
+        string $defaultAlg = null
+    ) {
+        $this->jwksUri = $jwksUri;
+        $this->httpClient = $httpClient;
+        $this->httpFactory = $httpFactory;
+        $this->cache = $cache;
+        $this->expiresAfter = $expiresAfter;
+        $this->rateLimit = $rateLimit;
+        $this->defaultAlg = $defaultAlg;
+        $this->setCacheKeys();
+    }
+
+    /**
+     * @param string $keyId
+     * @return Key
+     */
+    public function offsetGet($keyId): Key
+    {
+        if (!$this->keyIdExists($keyId)) {
+            throw new OutOfBoundsException('Key ID not found');
+        }
+        return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
+    }
+
+    /**
+     * @param string $keyId
+     * @return bool
+     */
+    public function offsetExists($keyId): bool
+    {
+        return $this->keyIdExists($keyId);
+    }
+
+    /**
+     * @param string $offset
+     * @param Key $value
+     */
+    public function offsetSet($offset, $value): void
+    {
+        throw new LogicException('Method not implemented');
+    }
+
+    /**
+     * @param string $offset
+     */
+    public function offsetUnset($offset): void
+    {
+        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
+    {
+        if (null === $this->keySet) {
+            $item = $this->getCacheItem();
+            // Try to load keys from cache
+            if ($item->isHit()) {
+                // item found! retrieve it
+                $this->keySet = $item->get();
+                // 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);
+                }
+            }
+        }
+
+        if (!isset($this->keySet[$keyId])) {
+            if ($this->rateLimitExceeded()) {
+                return false;
+            }
+            $request = $this->httpFactory->createRequest('GET', $this->jwksUri);
+            $jwksResponse = $this->httpClient->sendRequest($request);
+            $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
+
+            if (!isset($this->keySet[$keyId])) {
+                return false;
+            }
+
+            $item = $this->getCacheItem();
+            $item->set($this->keySet);
+            if ($this->expiresAfter) {
+                $item->expiresAfter($this->expiresAfter);
+            }
+            $this->cache->save($item);
+        }
+
+        return true;
+    }
+
+    private function rateLimitExceeded(): bool
+    {
+        if (!$this->rateLimit) {
+            return false;
+        }
+
+        $cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
+        if (!$cacheItem->isHit()) {
+            $cacheItem->expiresAfter(1); // # of calls are cached each minute
+        }
+
+        $callsPerMinute = (int) $cacheItem->get();
+        if (++$callsPerMinute > $this->maxCallsPerMinute) {
+            return true;
+        }
+        $cacheItem->set($callsPerMinute);
+        $this->cache->save($cacheItem);
+        return false;
+    }
+
+    private function getCacheItem(): CacheItemInterface
+    {
+        if (\is_null($this->cacheItem)) {
+            $this->cacheItem = $this->cache->getItem($this->cacheKey);
+        }
+
+        return $this->cacheItem;
+    }
+
+    private function setCacheKeys(): void
+    {
+        if (empty($this->jwksUri)) {
+            throw new RuntimeException('JWKS URI is empty');
+        }
+
+        // ensure we do not have illegal characters
+        $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $this->jwksUri);
+
+        // add prefix
+        $key = $this->cacheKeyPrefix . $key;
+
+        // Hash keys if they exceed $maxKeyLength of 64
+        if (\strlen($key) > $this->maxKeyLength) {
+            $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
+        }
+
+        $this->cacheKey = $key;
+
+        if ($this->rateLimit) {
+            // add prefix
+            $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key;
+
+            // Hash keys if they exceed $maxKeyLength of 64
+            if (\strlen($rateLimitKey) > $this->maxKeyLength) {
+                $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength);
+            }
+
+            $this->rateLimitCacheKey = $rateLimitKey;
+        }
+    }
+}

+ 176 - 25
data/web/inc/lib/vendor/firebase/php-jwt/src/JWK.php

@@ -20,12 +20,25 @@ use UnexpectedValueException;
  */
 class JWK
 {
+    private const OID = '1.2.840.10045.2.1';
+    private const ASN1_OBJECT_IDENTIFIER = 0x06;
+    private const ASN1_SEQUENCE = 0x10; // also defined in JWT
+    private const ASN1_BIT_STRING = 0x03;
+    private const EC_CURVES = [
+        '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-521' => '1.3.132.0.35', // Len: 132 (not supported)
+    ];
+
     /**
      * Parse a set of JWK keys
      *
-     * @param array $jwks The JSON Web Key Set as an associative array
+     * @param array<mixed> $jwks The JSON Web Key Set as an associative array
+     * @param string       $defaultAlg The algorithm for the Key object if "alg" is not set in the
+     *                                 JSON Web Key Set
      *
-     * @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
@@ -33,21 +46,22 @@ class JWK
      *
      * @uses parseKey
      */
-    public static function parseKeySet(array $jwks)
+    public static function parseKeySet(array $jwks, string $defaultAlg = null): array
     {
-        $keys = array();
+        $keys = [];
 
         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');
         }
 
         foreach ($jwks['keys'] as $k => $v) {
             $kid = isset($v['kid']) ? $v['kid'] : $k;
-            if ($key = self::parseKey($v)) {
-                $keys[$kid] = $key;
+            if ($key = self::parseKey($v, $defaultAlg)) {
+                $keys[(string) $kid] = $key;
             }
         }
 
@@ -61,9 +75,11 @@ class JWK
     /**
      * Parse a JWK key
      *
-     * @param array $jwk An individual JWK
+     * @param array<mixed> $jwk An individual JWK
+     * @param string       $defaultAlg The algorithm for the Key object if "alg" is not set in the
+     *                                 JSON Web Key Set
      *
-     * @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
@@ -71,15 +87,27 @@ class JWK
      *
      * @uses createPemFromModulusAndExponent
      */
-    public static function parseKey(array $jwk)
+    public static function parseKey(array $jwk, string $defaultAlg = null): ?Key
     {
         if (empty($jwk)) {
             throw new InvalidArgumentException('JWK must not be empty');
         }
+
         if (!isset($jwk['kty'])) {
             throw new UnexpectedValueException('JWK must contain a "kty" parameter');
         }
 
+        if (!isset($jwk['alg'])) {
+            if (\is_null($defaultAlg)) {
+                // The "alg" parameter is optional in a KTY, but an algorithm is required
+                // for parsing in this library. Use the $defaultAlg parameter when parsing the
+                // key set in order to prevent this error.
+                // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
+                throw new UnexpectedValueException('JWK must contain an "alg" parameter');
+            }
+            $jwk['alg'] = $defaultAlg;
+        }
+
         switch ($jwk['kty']) {
             case 'RSA':
                 if (!empty($jwk['d'])) {
@@ -96,11 +124,72 @@ class JWK
                         'OpenSSL error: ' . \openssl_error_string()
                     );
                 }
-                return $publicKey;
+                return new Key($publicKey, $jwk['alg']);
+            case 'EC':
+                if (isset($jwk['d'])) {
+                    // The key is actually a private key
+                    throw new UnexpectedValueException('Key data must be for a public key');
+                }
+
+                if (empty($jwk['crv'])) {
+                    throw new UnexpectedValueException('crv not set');
+                }
+
+                if (!isset(self::EC_CURVES[$jwk['crv']])) {
+                    throw new DomainException('Unrecognised or unsupported EC curve');
+                }
+
+                if (empty($jwk['x']) || empty($jwk['y'])) {
+                    throw new UnexpectedValueException('x and y not set');
+                }
+
+                $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
+                return new Key($publicKey, $jwk['alg']);
             default:
                 // Currently only RSA is supported
                 break;
         }
+
+        return null;
+    }
+
+    /**
+     * Converts the EC JWK values to pem format.
+     *
+     * @param   string  $crv The EC curve (only P-256 is supported)
+     * @param   string  $x   The EC x-coordinate
+     * @param   string  $y   The EC y-coordinate
+     *
+     * @return  string
+     */
+    private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y): string
+    {
+        $pem =
+            self::encodeDER(
+                self::ASN1_SEQUENCE,
+                self::encodeDER(
+                    self::ASN1_SEQUENCE,
+                    self::encodeDER(
+                        self::ASN1_OBJECT_IDENTIFIER,
+                        self::encodeOID(self::OID)
+                    )
+                    . self::encodeDER(
+                        self::ASN1_OBJECT_IDENTIFIER,
+                        self::encodeOID(self::EC_CURVES[$crv])
+                    )
+                ) .
+                self::encodeDER(
+                    self::ASN1_BIT_STRING,
+                    \chr(0x00) . \chr(0x04)
+                    . JWT::urlsafeB64Decode($x)
+                    . JWT::urlsafeB64Decode($y)
+                )
+            );
+
+        return sprintf(
+            "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
+            wordwrap(base64_encode($pem), 64, "\n", true)
+        );
     }
 
     /**
@@ -113,22 +202,22 @@ class JWK
      *
      * @uses encodeLength
      */
-    private static function createPemFromModulusAndExponent($n, $e)
-    {
-        $modulus = JWT::urlsafeB64Decode($n);
-        $publicExponent = JWT::urlsafeB64Decode($e);
+    private static function createPemFromModulusAndExponent(
+        string $n,
+        string $e
+    ): string {
+        $mod = JWT::urlsafeB64Decode($n);
+        $exp = JWT::urlsafeB64Decode($e);
 
-        $components = array(
-            'modulus' => \pack('Ca*a*', 2, self::encodeLength(\strlen($modulus)), $modulus),
-            'publicExponent' => \pack('Ca*a*', 2, self::encodeLength(\strlen($publicExponent)), $publicExponent)
-        );
+        $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
+        $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
 
         $rsaPublicKey = \pack(
             'Ca*a*a*',
             48,
-            self::encodeLength(\strlen($components['modulus']) + \strlen($components['publicExponent'])),
-            $components['modulus'],
-            $components['publicExponent']
+            self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
+            $modulus,
+            $publicExponent
         );
 
         // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
@@ -143,11 +232,9 @@ class JWK
             $rsaOID . $rsaPublicKey
         );
 
-        $rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
+        return "-----BEGIN PUBLIC KEY-----\r\n" .
             \chunk_split(\base64_encode($rsaPublicKey), 64) .
             '-----END PUBLIC KEY-----';
-
-        return $rsaPublicKey;
     }
 
     /**
@@ -159,7 +246,7 @@ class JWK
      * @param int $length
      * @return string
      */
-    private static function encodeLength($length)
+    private static function encodeLength(int $length): string
     {
         if ($length <= 0x7F) {
             return \chr($length);
@@ -169,4 +256,68 @@ class JWK
 
         return \pack('Ca*', 0x80 | \strlen($temp), $temp);
     }
+
+    /**
+     * Encodes a value into a DER object.
+     * Also defined in Firebase\JWT\JWT
+     *
+     * @param   int     $type DER tag
+     * @param   string  $value the value to encode
+     * @return  string  the encoded object
+     */
+    private static function encodeDER(int $type, string $value): string
+    {
+        $tag_header = 0;
+        if ($type === self::ASN1_SEQUENCE) {
+            $tag_header |= 0x20;
+        }
+
+        // Type
+        $der = \chr($tag_header | $type);
+
+        // Length
+        $der .= \chr(\strlen($value));
+
+        return $der . $value;
+    }
+
+    /**
+     * Encodes a string into a DER-encoded OID.
+     *
+     * @param   string $oid the OID string
+     * @return  string the binary DER-encoded OID
+     */
+    private static function encodeOID(string $oid): string
+    {
+        $octets = explode('.', $oid);
+
+        // Get the first octet
+        $first = (int) array_shift($octets);
+        $second = (int) array_shift($octets);
+        $oid = \chr($first * 40 + $second);
+
+        // Iterate over subsequent octets
+        foreach ($octets as $octet) {
+            if ($octet == 0) {
+                $oid .= \chr(0x00);
+                continue;
+            }
+            $bin = '';
+
+            while ($octet) {
+                $bin .= \chr(0x80 | ($octet & 0x7f));
+                $octet >>= 7;
+            }
+            $bin[0] = $bin[0] & \chr(0x7f);
+
+            // Convert to big endian if necessary
+            if (pack('V', 65534) == pack('L', 65534)) {
+                $oid .= strrev($bin);
+            } else {
+                $oid .= $bin;
+            }
+        }
+
+        return $oid;
+    }
 }

+ 210 - 179
data/web/inc/lib/vendor/firebase/php-jwt/src/JWT.php

@@ -3,12 +3,14 @@
 namespace Firebase\JWT;
 
 use ArrayAccess;
+use DateTime;
 use DomainException;
 use Exception;
 use InvalidArgumentException;
 use OpenSSLAsymmetricKey;
+use OpenSSLCertificate;
+use stdClass;
 use UnexpectedValueException;
-use DateTime;
 
 /**
  * JSON Web Token implementation, based on this spec:
@@ -25,52 +27,62 @@ use DateTime;
  */
 class JWT
 {
-    const ASN1_INTEGER = 0x02;
-    const ASN1_SEQUENCE = 0x10;
-    const ASN1_BIT_STRING = 0x03;
+    private const ASN1_INTEGER = 0x02;
+    private const ASN1_SEQUENCE = 0x10;
+    private const ASN1_BIT_STRING = 0x03;
 
     /**
      * When checking nbf, iat or expiration times,
      * we want to provide some extra leeway time to
      * account for clock skew.
+     *
+     * @var int
      */
     public static $leeway = 0;
 
     /**
      * Allow the current timestamp to be specified.
      * Useful for fixing a value within unit testing.
-     *
      * Will default to PHP time() value if null.
+     *
+     * @var ?int
      */
     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'),
-        'HS512' => array('hash_hmac', 'SHA512'),
-        'RS256' => array('openssl', 'SHA256'),
-        'RS384' => array('openssl', 'SHA384'),
-        'RS512' => array('openssl', 'SHA512'),
-        'EdDSA' => array('sodium_crypto', 'EdDSA'),
-    );
+    /**
+     * @var array<string, string[]>
+     */
+    public static $supported_algs = [
+        'ES384' => ['openssl', 'SHA384'],
+        'ES256' => ['openssl', 'SHA256'],
+        'ES256K' => ['openssl', 'SHA256'],
+        'HS256' => ['hash_hmac', 'SHA256'],
+        'HS384' => ['hash_hmac', 'SHA384'],
+        'HS512' => ['hash_hmac', 'SHA512'],
+        'RS256' => ['openssl', 'SHA256'],
+        'RS384' => ['openssl', 'SHA384'],
+        'RS512' => ['openssl', 'SHA512'],
+        'EdDSA' => ['sodium_crypto', 'EdDSA'],
+    ];
 
     /**
      * Decodes a JWT string into a PHP object.
      *
-     * @param string                    $jwt            The JWT
-     * @param Key|array<Key>|mixed      $keyOrKeyArray  The Key or array of Key objects.
-     *                                                  If the algorithm used is asymmetric, this is the public key
-     *                                                  Each Key object contains an algorithm and matching key.
-     *                                                  Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
-     *                                                  'HS512', 'RS256', 'RS384', and 'RS512'
-     * @param array                     $allowed_algs   [DEPRECATED] List of supported verification algorithms. Only
-     *                                                  should be used for backwards  compatibility.
-     *
-     * @return object The JWT's payload as a PHP object
-     *
-     * @throws InvalidArgumentException     Provided JWT was empty
+     * @param string                 $jwt            The JWT
+     * @param Key|ArrayAccess<string,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.
+     *                                                                      Each Key object contains an algorithm and
+     *                                                                      matching key.
+     *                                                                      Supported algorithms are 'ES384','ES256',
+     *                                                                      'HS256', 'HS384', 'HS512', 'RS256', 'RS384'
+     *                                                                      and 'RS512'.
+     *
+     * @return stdClass The JWT's payload as a PHP object
+     *
+     * @throws InvalidArgumentException     Provided key/key-array was empty or malformed
+     * @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'
@@ -80,27 +92,37 @@ class JWT
      * @uses jsonDecode
      * @uses urlsafeB64Decode
      */
-    public static function decode($jwt, $keyOrKeyArray, array $allowed_algs = array())
-    {
+    public static function decode(
+        string $jwt,
+        $keyOrKeyArray
+    ): stdClass {
+        // Validate JWT
         $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
 
         if (empty($keyOrKeyArray)) {
             throw new InvalidArgumentException('Key may not be empty');
         }
         $tks = \explode('.', $jwt);
-        if (\count($tks) != 3) {
+        if (\count($tks) !== 3) {
             throw new UnexpectedValueException('Wrong number of segments');
         }
         list($headb64, $bodyb64, $cryptob64) = $tks;
-        if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) {
+        $headerRaw = static::urlsafeB64Decode($headb64);
+        if (null === ($header = static::jsonDecode($headerRaw))) {
             throw new UnexpectedValueException('Invalid header encoding');
         }
-        if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) {
+        $payloadRaw = static::urlsafeB64Decode($bodyb64);
+        if (null === ($payload = static::jsonDecode($payloadRaw))) {
             throw new UnexpectedValueException('Invalid claims encoding');
         }
-        if (false === ($sig = static::urlsafeB64Decode($cryptob64))) {
-            throw new UnexpectedValueException('Invalid signature encoding');
+        if (\is_array($payload)) {
+            // prevent PHP Fatal Error in edge-cases when payload is empty array
+            $payload = (object) $payload;
+        }
+        if (!$payload instanceof stdClass) {
+            throw new UnexpectedValueException('Payload must be a JSON object');
         }
+        $sig = static::urlsafeB64Decode($cryptob64);
         if (empty($header->alg)) {
             throw new UnexpectedValueException('Empty algorithm');
         }
@@ -108,31 +130,18 @@ class JWT
             throw new UnexpectedValueException('Algorithm not supported');
         }
 
-        list($keyMaterial, $algorithm) = self::getKeyMaterialAndAlgorithm(
-            $keyOrKeyArray,
-            empty($header->kid) ? null : $header->kid
-        );
+        $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null);
 
-        if (empty($algorithm)) {
-            // Use deprecated "allowed_algs" to determine if the algorithm is supported.
-            // This opens up the possibility of an attack in some implementations.
-            // @see https://github.com/firebase/php-jwt/issues/351
-            if (!\in_array($header->alg, $allowed_algs)) {
-                throw new UnexpectedValueException('Algorithm not allowed');
-            }
-        } else {
-            // Check the algorithm
-            if (!self::constantTimeEquals($algorithm, $header->alg)) {
-                // See issue #351
-                throw new UnexpectedValueException('Incorrect key for this algorithm');
-            }
+        // 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' || $header->alg === 'ES384') {
-            // OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
+        if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) {
+            // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures
             $sig = self::signatureToDER($sig);
         }
-
-        if (!static::verify("$headb64.$bodyb64", $sig, $keyMaterial, $header->alg)) {
+        if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) {
             throw new SignatureInvalidException('Signature verification failed');
         }
 
@@ -162,34 +171,37 @@ 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 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
+     * @param array<mixed>          $payload PHP array
+     * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
+     * @param string                $alg     Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
+     *                                       'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
+     * @param string                $keyId
+     * @param array<string, string> $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)
-    {
-        $header = array('typ' => 'JWT', 'alg' => $alg);
+    public static function encode(
+        array $payload,
+        $key,
+        string $alg,
+        string $keyId = null,
+        array $head = null
+    ): string {
+        $header = ['typ' => 'JWT', 'alg' => $alg];
         if ($keyId !== null) {
             $header['kid'] = $keyId;
         }
         if (isset($head) && \is_array($head)) {
             $header = \array_merge($head, $header);
         }
-        $segments = array();
-        $segments[] = static::urlsafeB64Encode(static::jsonEncode($header));
-        $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload));
+        $segments = [];
+        $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));
+        $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));
         $signing_input = \implode('.', $segments);
 
         $signature = static::sign($signing_input, $key, $alg);
@@ -201,67 +213,84 @@ class JWT
     /**
      * Sign a string with a given key and algorithm.
      *
-     * @param string            $msg    The message to sign
-     * @param string|resource   $key    The secret key
-     * @param string            $alg    The signing algorithm.
-     *                                  Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
-     *                                  'HS512', 'RS256', 'RS384', and 'RS512'
+     * @param string $msg  The message to sign
+     * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate  $key  The secret key.
+     * @param string $alg  Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
+     *                    'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
      *
      * @return string An encrypted message
      *
      * @throws DomainException Unsupported algorithm or bad key was specified
      */
-    public static function sign($msg, $key, $alg = 'HS256')
-    {
+    public static function sign(
+        string $msg,
+        $key,
+        string $alg
+    ): string {
         if (empty(static::$supported_algs[$alg])) {
             throw new DomainException('Algorithm not supported');
         }
         list($function, $algorithm) = static::$supported_algs[$alg];
         switch ($function) {
             case 'hash_hmac':
+                if (!\is_string($key)) {
+                    throw new InvalidArgumentException('key must be a string when using hmac');
+                }
                 return \hash_hmac($algorithm, $msg, $key, true);
             case 'openssl':
                 $signature = '';
-                $success = \openssl_sign($msg, $signature, $key, $algorithm);
+                $success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
                 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);
                 } elseif ($alg === 'ES384') {
                     $signature = self::signatureFromDER($signature, 384);
                 }
                 return $signature;
             case 'sodium_crypto':
-                if (!function_exists('sodium_crypto_sign_detached')) {
+                if (!\function_exists('sodium_crypto_sign_detached')) {
                     throw new DomainException('libsodium is not available');
                 }
+                if (!\is_string($key)) {
+                    throw new InvalidArgumentException('key must be a string when using EdDSA');
+                }
                 try {
                     // The last non-empty line is used as the key.
                     $lines = array_filter(explode("\n", $key));
-                    $key = base64_decode(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);
                 } catch (Exception $e) {
                     throw new DomainException($e->getMessage(), 0, $e);
                 }
         }
+
+        throw new DomainException('Algorithm not supported');
     }
 
     /**
      * Verify a signature with the message, key and method. Not all methods
      * are symmetric, so we must have a separate verify and sign method.
      *
-     * @param string            $msg        The original message (header and body)
-     * @param string            $signature  The original signature
-     * @param string|resource   $key        For HS*, a string key works. for RS*, must be a resource of an openssl public key
-     * @param string            $alg        The algorithm
+     * @param string $msg         The original message (header and body)
+     * @param string $signature   The original signature
+     * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate  $keyMaterial For HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
+     * @param string $alg         The algorithm
      *
      * @return bool
      *
      * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
      */
-    private static function verify($msg, $signature, $key, $alg)
-    {
+    private static function verify(
+        string $msg,
+        string $signature,
+        $keyMaterial,
+        string $alg
+    ): bool {
         if (empty(static::$supported_algs[$alg])) {
             throw new DomainException('Algorithm not supported');
         }
@@ -269,10 +298,11 @@ class JWT
         list($function, $algorithm) = static::$supported_algs[$alg];
         switch ($function) {
             case 'openssl':
-                $success = \openssl_verify($msg, $signature, $key, $algorithm);
+                $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
                 if ($success === 1) {
                     return true;
-                } elseif ($success === 0) {
+                }
+                if ($success === 0) {
                     return false;
                 }
                 // returns 1 on success, 0 on failure, -1 on error.
@@ -280,21 +310,33 @@ class JWT
                     '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);
-              }
+                if (!\function_exists('sodium_crypto_sign_verify_detached')) {
+                    throw new DomainException('libsodium is not available');
+                }
+                if (!\is_string($keyMaterial)) {
+                    throw new InvalidArgumentException('key must be a string when using EdDSA');
+                }
+                try {
+                    // The last non-empty line is used as the key.
+                    $lines = array_filter(explode("\n", $keyMaterial));
+                    $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);
+                } catch (Exception $e) {
+                    throw new DomainException($e->getMessage(), 0, $e);
+                }
             case 'hash_hmac':
             default:
-                $hash = \hash_hmac($algorithm, $msg, $key, true);
-                return self::constantTimeEquals($signature, $hash);
+                if (!\is_string($keyMaterial)) {
+                    throw new InvalidArgumentException('key must be a string when using hmac');
+                }
+                $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
+                return self::constantTimeEquals($hash, $signature);
         }
     }
 
@@ -303,30 +345,16 @@ class JWT
      *
      * @param string $input JSON string
      *
-     * @return object Object representation of JSON string
+     * @return mixed The decoded JSON string
      *
      * @throws DomainException Provided string was invalid JSON
      */
-    public static function jsonDecode($input)
+    public static function jsonDecode(string $input)
     {
-        if (\version_compare(PHP_VERSION, '5.4.0', '>=') && !(\defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
-            /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
-             * to specify that large ints (like Steam Transaction IDs) should be treated as
-             * strings, rather than the PHP default behaviour of converting them to floats.
-             */
-            $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
-        } else {
-            /** Not all servers will support that, however, so for older versions we must
-             * manually detect large ints in the JSON string and quote them (thus converting
-             *them to strings) before decoding, hence the preg_replace() call.
-             */
-            $max_int_length = \strlen((string) PHP_INT_MAX) - 1;
-            $json_without_bigints = \preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
-            $obj = \json_decode($json_without_bigints);
-        }
+        $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
 
         if ($errno = \json_last_error()) {
-            static::handleJsonError($errno);
+            self::handleJsonError($errno);
         } elseif ($obj === null && $input !== 'null') {
             throw new DomainException('Null result with non-null input');
         }
@@ -334,22 +362,30 @@ class JWT
     }
 
     /**
-     * Encode a PHP object into a JSON string.
+     * Encode a PHP array into a JSON string.
      *
-     * @param object|array $input A PHP object or array
+     * @param array<mixed> $input A PHP array
      *
-     * @return string JSON representation of the PHP object or array
+     * @return string JSON representation of the PHP array
      *
      * @throws DomainException Provided object could not be encoded to valid JSON
      */
-    public static function jsonEncode($input)
+    public static function jsonEncode(array $input): string
     {
-        $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) {
+            self::handleJsonError($errno);
+        } elseif ($json === 'null') {
             throw new DomainException('Null result with non-null input');
         }
+        if ($json === false) {
+            throw new DomainException('Provided object could not be encoded to valid JSON');
+        }
         return $json;
     }
 
@@ -359,8 +395,10 @@ class JWT
      * @param string $input A Base64 encoded string
      *
      * @return string A decoded string
+     *
+     * @throws InvalidArgumentException invalid base64 characters
      */
-    public static function urlsafeB64Decode($input)
+    public static function urlsafeB64Decode(string $input): string
     {
         $remainder = \strlen($input) % 4;
         if ($remainder) {
@@ -377,7 +415,7 @@ class JWT
      *
      * @return string The base64 encode of what you passed in
      */
-    public static function urlsafeB64Encode($input)
+    public static function urlsafeB64Encode(string $input): string
     {
         return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
     }
@@ -386,67 +424,54 @@ class JWT
     /**
      * Determine if an algorithm has been provided for each Key
      *
-     * @param Key|array<Key>|mixed $keyOrKeyArray
-     * @param string|null $kid
+     * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray
+     * @param string|null            $kid
      *
      * @throws UnexpectedValueException
      *
-     * @return array containing the keyMaterial and algorithm
+     * @return Key
      */
-    private static function getKeyMaterialAndAlgorithm($keyOrKeyArray, $kid = null)
-    {
-        if (
-            is_string($keyOrKeyArray)
-            || is_resource($keyOrKeyArray)
-            || $keyOrKeyArray instanceof OpenSSLAsymmetricKey
-        ) {
-            return array($keyOrKeyArray, null);
-        }
-
+    private static function getKey(
+        $keyOrKeyArray,
+        ?string $kid
+    ): Key {
         if ($keyOrKeyArray instanceof Key) {
-            return array($keyOrKeyArray->getKeyMaterial(), $keyOrKeyArray->getAlgorithm());
+            return $keyOrKeyArray;
         }
 
-        if (is_array($keyOrKeyArray) || $keyOrKeyArray instanceof ArrayAccess) {
-            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');
-            }
-
-            $key = $keyOrKeyArray[$kid];
+        if (empty($kid) && $kid !== '0') {
+            throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
+        }
 
-            if ($key instanceof Key) {
-                return array($key->getKeyMaterial(), $key->getAlgorithm());
-            }
+        if ($keyOrKeyArray instanceof CachedKeySet) {
+            // Skip "isset" check, as this will automatically refresh if not set
+            return $keyOrKeyArray[$kid];
+        }
 
-            return array($key, null);
+        if (!isset($keyOrKeyArray[$kid])) {
+            throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
         }
 
-        throw new UnexpectedValueException(
-            '$keyOrKeyArray must be a string|resource key, an array of string|resource keys, '
-            . 'an instance of Firebase\JWT\Key key or an array of Firebase\JWT\Key keys'
-        );
+        return $keyOrKeyArray[$kid];
     }
 
     /**
-     * @param string $left
-     * @param string $right
+     * @param string $left  The string of known length to compare against
+     * @param string $right The user-supplied string
      * @return bool
      */
-    public static function constantTimeEquals($left, $right)
+    public static function constantTimeEquals(string $left, string $right): bool
     {
         if (\function_exists('hash_equals')) {
             return \hash_equals($left, $right);
         }
-        $len = \min(static::safeStrlen($left), static::safeStrlen($right));
+        $len = \min(self::safeStrlen($left), self::safeStrlen($right));
 
         $status = 0;
         for ($i = 0; $i < $len; $i++) {
             $status |= (\ord($left[$i]) ^ \ord($right[$i]));
         }
-        $status |= (static::safeStrlen($left) ^ static::safeStrlen($right));
+        $status |= (self::safeStrlen($left) ^ self::safeStrlen($right));
 
         return ($status === 0);
     }
@@ -456,17 +481,19 @@ class JWT
      *
      * @param int $errno An error number from json_last_error()
      *
+     * @throws DomainException
+     *
      * @return void
      */
-    private static function handleJsonError($errno)
+    private static function handleJsonError(int $errno): void
     {
-        $messages = array(
+        $messages = [
             JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
             JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
             JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
             JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
             JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3
-        );
+        ];
         throw new DomainException(
             isset($messages[$errno])
             ? $messages[$errno]
@@ -481,7 +508,7 @@ class JWT
      *
      * @return int
      */
-    private static function safeStrlen($str)
+    private static function safeStrlen(string $str): int
     {
         if (\function_exists('mb_strlen')) {
             return \mb_strlen($str, '8bit');
@@ -495,10 +522,11 @@ class JWT
      * @param   string $sig The ECDSA signature to convert
      * @return  string The encoded DER object
      */
-    private static function signatureToDER($sig)
+    private static function signatureToDER(string $sig): string
     {
         // Separate the signature into r-value and s-value
-        list($r, $s) = \str_split($sig, (int) (\strlen($sig) / 2));
+        $length = max(1, (int) (\strlen($sig) / 2));
+        list($r, $s) = \str_split($sig, $length);
 
         // Trim leading zeros
         $r = \ltrim($r, "\x00");
@@ -525,9 +553,10 @@ class JWT
      *
      * @param   int     $type DER tag
      * @param   string  $value the value to encode
+     *
      * @return  string  the encoded object
      */
-    private static function encodeDER($type, $value)
+    private static function encodeDER(int $type, string $value): string
     {
         $tag_header = 0;
         if ($type === self::ASN1_SEQUENCE) {
@@ -548,9 +577,10 @@ class JWT
      *
      * @param   string  $der binary signature in DER format
      * @param   int     $keySize the number of bits in the key
+     *
      * @return  string  the signature
      */
-    private static function signatureFromDER($der, $keySize)
+    private static function signatureFromDER(string $der, int $keySize): string
     {
         // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
         list($offset, $_) = self::readDER($der);
@@ -575,9 +605,10 @@ class JWT
      * @param string $der the binary data in DER format
      * @param int $offset the offset of the data stream containing the object
      * to decode
-     * @return array [$offset, $data] the new offset and the decoded object
+     *
+     * @return array{int, string|null} the new offset and the decoded object
      */
-    private static function readDER($der, $offset = 0)
+    private static function readDER(string $der, int $offset = 0): array
     {
         $pos = $offset;
         $size = \strlen($der);
@@ -595,7 +626,7 @@ class JWT
         }
 
         // Value
-        if ($type == self::ASN1_BIT_STRING) {
+        if ($type === self::ASN1_BIT_STRING) {
             $pos++; // Skip the first contents octet (padding indicator)
             $data = \substr($der, $pos, $len - 1);
             $pos += $len - 1;
@@ -606,6 +637,6 @@ class JWT
             $data = null;
         }
 
-        return array($pos, $data);
+        return [$pos, $data];
     }
 }

+ 20 - 15
data/web/inc/lib/vendor/firebase/php-jwt/src/Key.php

@@ -4,37 +4,42 @@ namespace Firebase\JWT;
 
 use InvalidArgumentException;
 use OpenSSLAsymmetricKey;
+use OpenSSLCertificate;
+use TypeError;
 
 class Key
 {
-    /** @var string $algorithm */
-    private $algorithm;
-
-    /** @var string|resource|OpenSSLAsymmetricKey $keyMaterial */
+    /** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */
     private $keyMaterial;
+    /** @var string */
+    private $algorithm;
 
     /**
-     * @param string|resource|OpenSSLAsymmetricKey $keyMaterial
+     * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
      * @param string $algorithm
      */
-    public function __construct($keyMaterial, $algorithm)
-    {
+    public function __construct(
+        $keyMaterial,
+        string $algorithm
+    ) {
         if (
-            !is_string($keyMaterial)
-            && !is_resource($keyMaterial)
+            !\is_string($keyMaterial)
             && !$keyMaterial instanceof OpenSSLAsymmetricKey
+            && !$keyMaterial instanceof OpenSSLCertificate
+            && !\is_resource($keyMaterial)
         ) {
-            throw new InvalidArgumentException('Type error: $keyMaterial must be a string, resource, or OpenSSLAsymmetricKey');
+            throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
         }
 
         if (empty($keyMaterial)) {
-            throw new InvalidArgumentException('Type error: $keyMaterial must not be empty');
+            throw new InvalidArgumentException('Key material must not be empty');
         }
 
-        if (!is_string($algorithm)|| empty($keyMaterial)) {
-            throw new InvalidArgumentException('Type error: $algorithm must be a string');
+        if (empty($algorithm)) {
+            throw new InvalidArgumentException('Algorithm must not be empty');
         }
 
+        // TODO: Remove in PHP 8.0 in favor of class constructor property promotion
         $this->keyMaterial = $keyMaterial;
         $this->algorithm = $algorithm;
     }
@@ -44,13 +49,13 @@ class Key
      *
      * @return string
      */
-    public function getAlgorithm()
+    public function getAlgorithm(): string
     {
         return $this->algorithm;
     }
 
     /**
-     * @return string|resource|OpenSSLAsymmetricKey
+     * @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
      */
     public function getKeyMaterial()
     {

+ 6 - 3
data/web/inc/lib/vendor/stevenmaguire/oauth2-keycloak/.travis.yml

@@ -3,9 +3,12 @@ language: php
 sudo: false
 
 php:
-  - 5.6
-  - 7.0
-  - 7.1
+  - 7.2
+  - 7.3
+  - 7.4
+  - 8.0
+  - 8.1
+  - 8.2
 
 matrix:
   include:

+ 1 - 0
data/web/inc/lib/vendor/stevenmaguire/oauth2-keycloak/README.md

@@ -36,6 +36,7 @@ $provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
     'encryptionAlgorithm'   => 'RS256',                             // optional
     'encryptionKeyPath'     => '../key.pem'                         // optional
     'encryptionKey'         => 'contents_of_key_or_certificate'     // optional
+    'version'               => '20.0.1',                            // optional
 ]);
 
 if (!isset($_GET['code'])) {

+ 12 - 5
data/web/inc/lib/vendor/stevenmaguire/oauth2-keycloak/composer.json

@@ -18,13 +18,14 @@
         "keycloak"
     ],
     "require": {
+        "php": "~7.2 || ~8.0",
         "league/oauth2-client": "^2.0",
-        "firebase/php-jwt": "~4.0|~5.0"
+        "firebase/php-jwt": "^4.0 || ^5.0 || ^6.0"
     },
     "require-dev": {
-        "phpunit/phpunit": "~4.0",
-        "mockery/mockery": "~0.9",
-        "squizlabs/php_codesniffer": "~2.0"
+        "phpunit/phpunit": "~9.6.4",
+        "mockery/mockery": "~1.5.0",
+        "squizlabs/php_codesniffer": "~3.7.0"
     },
     "autoload": {
         "psr-4": {
@@ -40,5 +41,11 @@
         "branch-alias": {
             "dev-master": "1.0.x-dev"
         }
+    },
+    "scripts": {
+        "test": [
+            "@putenv XDEBUG_MODE=coverage",
+            "phpunit --colors=always"
+        ]
     }
-}
+}

+ 20 - 25
data/web/inc/lib/vendor/stevenmaguire/oauth2-keycloak/phpunit.xml.dist

@@ -1,38 +1,33 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <phpunit backupGlobals="false"
-         backupStaticAttributes="false"
          bootstrap="vendor/autoload.php"
          colors="true"
-         convertErrorsToExceptions="true"
-         convertNoticesToExceptions="true"
-         convertWarningsToExceptions="true"
          processIsolation="false"
          stopOnFailure="false"
-         syntaxCheck="false"
+         failOnRisky="true"
+         failOnWarning="true"
 >
-    <logging>
-        <log type="coverage-html"
-                target="./build/coverage/html"
-                charset="UTF-8"
-                highlight="false"
-                lowUpperBound="35"
-                highLowerBound="70"/>
-          <log type="coverage-clover"
-                target="./build/coverage/log/coverage.xml"/>
-    </logging>
+    <coverage includeUncoveredFiles="true"
+              pathCoverage="false"
+              ignoreDeprecatedCodeUnits="true"
+              disableCodeCoverageIgnore="true">
+        <include>
+            <directory suffix=".php">src</directory>
+        </include>
+        <exclude>
+            <directory suffix=".php">vendor</directory>
+            <file>src/autoload.php</file>
+        </exclude>
+        <report>
+            <html outputDirectory="./build/coverage/html"
+                  lowUpperBound="35"
+                  highLowerBound="70"/>
+            <clover outputFile="./build/coverage/log/coverage.xml"/>
+        </report>
+    </coverage>
     <testsuites>
         <testsuite name="Package Test Suite">
             <directory suffix=".php">./test/</directory>
         </testsuite>
     </testsuites>
-    <filter>
-        <whitelist>
-            <directory suffix=".php">./</directory>
-            <exclude>
-                <directory suffix=".php">./examples</directory>
-                <directory suffix=".php">./vendor</directory>
-                <directory suffix=".php">./test</directory>
-            </exclude>
-        </whitelist>
-    </filter>
 </phpunit>

+ 80 - 44
data/web/inc/lib/vendor/stevenmaguire/oauth2-keycloak/test/src/Provider/KeycloakTest.php

@@ -23,18 +23,22 @@ namespace Stevenmaguire\OAuth2\Client\Provider
 
 namespace Stevenmaguire\OAuth2\Client\Test\Provider
 {
+    use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
     use League\OAuth2\Client\Tool\QueryBuilderTrait;
     use Mockery as m;
+    use PHPUnit\Framework\TestCase;
+    use Stevenmaguire\OAuth2\Client\Provider\Exception\EncryptionConfigurationException;
+    use Stevenmaguire\OAuth2\Client\Provider\Keycloak;
 
-    class KeycloakTest extends \PHPUnit_Framework_TestCase
+    class KeycloakTest extends TestCase
     {
         use QueryBuilderTrait;
 
         protected $provider;
 
-        protected function setUp()
+        protected function setUp(): void
         {
-            $this->provider = new \Stevenmaguire\OAuth2\Client\Provider\Keycloak([
+            $this->provider = new Keycloak([
                 'authServerUrl' => 'http://mock.url/auth',
                 'realm' => 'mock_realm',
                 'clientId' => 'mock_client_id',
@@ -43,7 +47,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             ]);
         }
 
-        public function tearDown()
+        public function tearDown(): void
         {
             m::close();
             parent::tearDown();
@@ -67,7 +71,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
         public function testEncryptionAlgorithm()
         {
             $algorithm = uniqid();
-            $provider = new \Stevenmaguire\OAuth2\Client\Provider\Keycloak([
+            $provider = new Keycloak([
                 'encryptionAlgorithm' => $algorithm,
             ]);
 
@@ -82,7 +86,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
         public function testEncryptionKey()
         {
             $key = uniqid();
-            $provider = new \Stevenmaguire\OAuth2\Client\Provider\Keycloak([
+            $provider = new Keycloak([
                 'encryptionKey' => $key,
             ]);
 
@@ -101,7 +105,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             $key = uniqid();
             $mockFileGetContents = $key;
 
-            $provider = new \Stevenmaguire\OAuth2\Client\Provider\Keycloak([
+            $provider = new Keycloak([
                 'encryptionKeyPath' => $path,
             ]);
 
@@ -118,12 +122,14 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
 
         public function testEncryptionKeyPathFails()
         {
+            $this->markTestIncomplete('Need to assess the test to see what is required to be checked.');
+
             global $mockFileGetContents;
             $path = uniqid();
             $key = uniqid();
             $mockFileGetContents = new \Exception();
 
-            $provider = new \Stevenmaguire\OAuth2\Client\Provider\Keycloak([
+            $provider = new Keycloak([
                 'encryptionKeyPath' => $path,
             ]);
 
@@ -137,7 +143,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             $query = ['scope' => implode($scopeSeparator, $options['scope'])];
             $url = $this->provider->getAuthorizationUrl($options);
             $encodedScope = $this->buildQueryString($query);
-            $this->assertContains($encodedScope, $url);
+            $this->assertStringContainsString($encodedScope, $url);
         }
 
         public function testGetAuthorizationUrl()
@@ -169,11 +175,15 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
         public function testGetAccessToken()
         {
             $response = m::mock('Psr\Http\Message\ResponseInterface');
-            $response->shouldReceive('getBody')->andReturn('{"access_token":"mock_access_token", "scope":"email", "token_type":"bearer"}');
-            $response->shouldReceive('getHeader')->andReturn(['content-type' => 'json']);
+            $response->shouldReceive('getBody')
+                ->andReturn('{"access_token":"mock_access_token", "scope":"email", "token_type":"bearer"}');
+            $response->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'json']);
 
             $client = m::mock('GuzzleHttp\ClientInterface');
-            $client->shouldReceive('send')->times(1)->andReturn($response);
+            $client->shouldReceive('send')
+                ->times(1)
+                ->andReturn($response);
             $this->provider->setHttpClient($client);
 
             $token = $this->provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']);
@@ -186,18 +196,24 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
 
         public function testUserData()
         {
-            $userId = rand(1000,9999);
+            $userId = rand(1000, 9999);
             $name = uniqid();
             $nickname = uniqid();
             $email = uniqid();
 
             $postResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $postResponse->shouldReceive('getBody')->andReturn('access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}');
-            $postResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
+            $postResponse->shouldReceive('getBody')
+                ->andReturn(
+                    'access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}'
+                );
+            $postResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
 
             $userResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $userResponse->shouldReceive('getBody')->andReturn('{"sub": '.$userId.', "name": "'.$name.'", "email": "'.$email.'"}');
-            $userResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'json']);
+            $userResponse->shouldReceive('getBody')
+                ->andReturn('{"sub": '.$userId.', "name": "'.$name.'", "email": "'.$email.'"}');
+            $userResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'json']);
 
             $client = m::mock('GuzzleHttp\ClientInterface');
             $client->shouldReceive('send')
@@ -218,7 +234,7 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
 
         public function testUserDataWithEncryption()
         {
-            $userId = rand(1000,9999);
+            $userId = rand(1000, 9999);
             $name = uniqid();
             $nickname = uniqid();
             $email = uniqid();
@@ -227,21 +243,31 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             $key = uniqid();
 
             $postResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $postResponse->shouldReceive('getBody')->andReturn('access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}');
-            $postResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
-            $postResponse->shouldReceive('getStatusCode')->andReturn(200);
+            $postResponse->shouldReceive('getBody')
+                ->andReturn(
+                    'access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}'
+                );
+            $postResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
+            $postResponse->shouldReceive('getStatusCode')
+                ->andReturn(200);
 
             $userResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $userResponse->shouldReceive('getBody')->andReturn($jwt);
-            $userResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'application/jwt']);
-            $userResponse->shouldReceive('getStatusCode')->andReturn(200);
+            $userResponse->shouldReceive('getBody')
+                ->andReturn($jwt);
+            $userResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'application/jwt']);
+            $userResponse->shouldReceive('getStatusCode')
+                ->andReturn(200);
 
             $decoder = \Mockery::mock('overload:Firebase\JWT\JWT');
-            $decoder->shouldReceive('decode')->with($jwt, $key, [$algorithm])->andReturn([
-                'sub' => $userId,
-                'email' => $email,
-                'name' => $name,
-            ]);
+            $decoder->shouldReceive('decode')
+                ->with($jwt, $key, [$algorithm])
+                ->andReturn([
+                    'sub' => $userId,
+                    'email' => $email,
+                    'name' => $name,
+                ]);
 
             $client = m::mock('GuzzleHttp\ClientInterface');
             $client->shouldReceive('send')
@@ -262,20 +288,27 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             $this->assertEquals($email, $user->toArray()['email']);
         }
 
-        /**
-         * @expectedException Stevenmaguire\OAuth2\Client\Provider\Exception\EncryptionConfigurationException
-         */
         public function testUserDataFailsWhenEncryptionEncounteredAndNotConfigured()
         {
+            $this->expectException(EncryptionConfigurationException::class);
+
             $postResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $postResponse->shouldReceive('getBody')->andReturn('access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}');
-            $postResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
-            $postResponse->shouldReceive('getStatusCode')->andReturn(200);
+            $postResponse->shouldReceive('getBody')
+                ->andReturn(
+                    'access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}'
+                );
+            $postResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'application/x-www-form-urlencoded']);
+            $postResponse->shouldReceive('getStatusCode')
+                ->andReturn(200);
 
             $userResponse = m::mock('Psr\Http\Message\ResponseInterface');
-            $userResponse->shouldReceive('getBody')->andReturn(uniqid());
-            $userResponse->shouldReceive('getHeader')->andReturn(['content-type' => 'application/jwt']);
-            $userResponse->shouldReceive('getStatusCode')->andReturn(200);
+            $userResponse->shouldReceive('getBody')
+                ->andReturn(uniqid());
+            $userResponse->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'application/jwt']);
+            $userResponse->shouldReceive('getStatusCode')
+                ->andReturn(200);
 
             $client = m::mock('GuzzleHttp\ClientInterface');
             $client->shouldReceive('send')
@@ -287,17 +320,20 @@ namespace Stevenmaguire\OAuth2\Client\Test\Provider
             $user = $this->provider->getResourceOwner($token);
         }
 
-        /**
-         * @expectedException League\OAuth2\Client\Provider\Exception\IdentityProviderException
-         */
         public function testErrorResponse()
         {
+            $this->expectException(IdentityProviderException::class);
+
             $response = m::mock('Psr\Http\Message\ResponseInterface');
-            $response->shouldReceive('getBody')->andReturn('{"error": "invalid_grant", "error_description": "Code not found"}');
-            $response->shouldReceive('getHeader')->andReturn(['content-type' => 'json']);
+            $response->shouldReceive('getBody')
+                ->andReturn('{"error": "invalid_grant", "error_description": "Code not found"}');
+            $response->shouldReceive('getHeader')
+                ->andReturn(['content-type' => 'json']);
 
             $client = m::mock('GuzzleHttp\ClientInterface');
-            $client->shouldReceive('send')->times(1)->andReturn($response);
+            $client->shouldReceive('send')
+                ->times(1)
+                ->andReturn($response);
             $this->provider->setHttpClient($client);
 
             $token = $this->provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']);