diff options
Diffstat (limited to 'vendor')
9 files changed, 618 insertions, 611 deletions
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 5cc79ce..166d410 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -71,30 +71,31 @@ }, { "name": "jumbojett/openid-connect-php", - "version": "v1.0.0", - "version_normalized": "1.0.0.0", + "version": "v0.9.10", + "version_normalized": "0.9.10.0", "source": { "type": "git", "url": "https://github.com/jumbojett/OpenID-Connect-PHP.git", - "reference": "4af1d11497ec765dccddf928c14c04535ca96017" + "reference": "45aac47b525f0483dd4db3324bb1f1cab4666061" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jumbojett/OpenID-Connect-PHP/zipball/4af1d11497ec765dccddf928c14c04535ca96017", - "reference": "4af1d11497ec765dccddf928c14c04535ca96017", + "url": "https://api.github.com/repos/jumbojett/OpenID-Connect-PHP/zipball/45aac47b525f0483dd4db3324bb1f1cab4666061", + "reference": "45aac47b525f0483dd4db3324bb1f1cab4666061", "shasum": "" }, "require": { "ext-curl": "*", "ext-json": "*", - "php": ">=7.0", - "phpseclib/phpseclib": "~3.0" + "paragonie/random_compat": ">=2", + "php": ">=5.4", + "phpseclib/phpseclib": "~2.0 || ^3.0" }, "require-dev": { - "roave/security-advisories": "dev-latest", + "roave/security-advisories": "dev-master", "yoast/phpunit-polyfills": "^1.0" }, - "time": "2023-12-13T09:52:12+00:00", + "time": "2022-09-30T12:34:46+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -109,7 +110,7 @@ "description": "Bare-bones OpenID Connect client", "support": { "issues": "https://github.com/jumbojett/OpenID-Connect-PHP/issues", - "source": "https://github.com/jumbojett/OpenID-Connect-PHP/tree/v1.0.0" + "source": "https://github.com/jumbojett/OpenID-Connect-PHP/tree/v0.9.10" }, "install-path": "../jumbojett/openid-connect-php" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 8b239c0..53605c3 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '4e441bac2b6770c9364f9a40e663833498a732ce', + 'reference' => '0f54e6e844935538b195816ccb703b2a51239adb', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,7 +13,7 @@ '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '4e441bac2b6770c9364f9a40e663833498a732ce', + 'reference' => '0f54e6e844935538b195816ccb703b2a51239adb', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -29,9 +29,9 @@ 'dev_requirement' => false, ), 'jumbojett/openid-connect-php' => array( - 'pretty_version' => 'v1.0.0', - 'version' => '1.0.0.0', - 'reference' => '4af1d11497ec765dccddf928c14c04535ca96017', + 'pretty_version' => 'v0.9.10', + 'version' => '0.9.10.0', + 'reference' => '45aac47b525f0483dd4db3324bb1f1cab4666061', 'type' => 'library', 'install_path' => __DIR__ . '/../jumbojett/openid-connect-php', 'aliases' => array(), diff --git a/vendor/jumbojett/openid-connect-php/.github/workflows/build.yml b/vendor/jumbojett/openid-connect-php/.github/workflows/build.yml index 515cd64..2033968 100644 --- a/vendor/jumbojett/openid-connect-php/.github/workflows/build.yml +++ b/vendor/jumbojett/openid-connect-php/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] steps: - name: Checkout diff --git a/vendor/jumbojett/openid-connect-php/CHANGELOG.md b/vendor/jumbojett/openid-connect-php/CHANGELOG.md index d4be9ff..eacd7d3 100644 --- a/vendor/jumbojett/openid-connect-php/CHANGELOG.md +++ b/vendor/jumbojett/openid-connect-php/CHANGELOG.md @@ -1,180 +1,185 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.0.0] - 2023-12-13 +## [0.9.10] -### Added -- PHP 7.0 is required. #327 -- Support for signed and encrypted UserInfo response and ID Token. #305 -- Allow to set User-Agent header. #370 - -### Fixed -- User-Agent is set for any HTTP method in fetchURL() (not just POST). #382 -- Update visibility of getWellKnownConfigValue to protected. #363 -- Fixed issue on authentication for php8. #354 -- Update construct typehint in docblock. #364 -- Fixed LogoutToken verification for single value aud claims. #334 -- Update well known config value function response types. #376 +## Fixed -## [0.9.10] - 2022-09-30 +* `private_key_jwt` and `client_secret_jwt` need to explicitly be enabled #331 -### Fixed -- `private_key_jwt` and `client_secret_jwt` need to explicitly be enabled #331 -## [0.9.9] - 2022-09-28 +## [0.9.9] ### Added -- Added support for back-channel logout. #302 -- Added support for `private_key_jwt` Client Authentication method #322 -- Added support for `client_secret_jwt` Client Authentication method #324 -- Added PS512 encryption support #342 -### Fixed -- Harden self-signed JWK header usage. #323 +* Added support for back-channel logout. #302 +* Added support for `private_key_jwt` Client Authentication method #322 +* Added support for `client_secret_jwt` Client Authentication method #324 +* Added PS512 encryption support #342 -## [0.9.8] - 2022-08-05 +## Fixed -### Fixed -- Do not use PKCE if IdP does not support it. #317 +* Harden self-signed JWK header usage. #323 + +## [0.9.8] -## [0.9.7] - 2022-07-13 +## Fixed + +* Do not use PKCE if IdP does not support it. #317 + +## [0.9.7] ### Added -- Support for Self-Contained JWTs. #308 -- Support for RFC8693 Token Exchange Request. #275 + +* Support for Self-Contained JWTs. #308 +* Support for RFC8693 Token Exchange Request. #275 ### Fixed -- PHP 5.4 compatibility. #304 -- Use session_status(). #306 -## [0.9.6] - 2022-05-08 +* PHP 5.4 compatibility. #304 +* Use session_status(). #306 + +## [0.9.6] ### Added -- Support for [phpseclib/phpseclib](https://phpseclib.com/) version **3**. #260 -- Support client_secret on token endpoint with PKCE. #293 -- Added new parameter to `requestTokens()` to pass custom HTTP headers #297 + +* Support for [phpseclib/phpseclib](https://phpseclib.com/) version **3**. #260 +* Support client_secret on token endpoint with PKCE. #293 +* Added new parameter to `requestTokens()` to pass custom HTTP headers #297 ### Changed -- Allow serializing `OpenIDConnectClient` using `serialize()` #295 -## [0.9.5] - 2021-11-24 +* Allow serializing `OpenIDConnectClient` using `serialize()` #295 + +## [0.9.5] ### Changed -- signOut() Method parameter $accessToken -> $idToken to prevent confusion about access and id tokens usage. #127 -- Fixed issue where missing nonce within the claims was causing an exception. #280 -## [0.9.4] - 2021-11-21 +* signOut() Method parameter $accessToken -> $idToken to prevent confusion about access and id tokens usage. #127 +* Fixed issue where missing nonce within the claims was causing an exception. #280 + +## [0.9.4] ### Added -- Enabled `client_secret_basic` authentication on `refreshToken()` #215 -- Basic auth support for requestResourceOwnerToken #271 -## [0.9.3] - 2021-11-20 +* Enabled `client_secret_basic` authentication on `refreshToken()` #215 +* Basic auth support for requestResourceOwnerToken #271 + +## [0.9.3] ### Added -- getRedirectURL() will not log a warning for PHP 7.1+ #179 -- it is now possible to disable upgrading from HTTP to HTTPS for development purposes by calling `setHttpUpgradeInsecureRequests(false)` #241 -- bugfix in getSessionKey when _SESSION key does not exist #251 -- Added scope parameter to refresh token request #225 -- bugfix in `verifyJWTclaims` when $accessToken is empty and $claims->at_hash is not #276 -- bugfix with the `empty` function in PHP 5.4 #267 -## [0.9.2] - 2020-11-16 +* getRedirectURL() will not log a warning for PHP 7.1+ #179 +* it is now possible to disable upgrading from HTTP to HTTPS for development purposes by calling `setHttpUpgradeInsecureRequests(false)` #241 +* bugfix in getSessionKey when _SESSION key does not exist #251 +* Added scope parameter to refresh token request #225 +* bugfix in `verifyJWTclaims` when $accessToken is empty and $claims->at_hash is not #276 +* bugfix with the `empty` function in PHP 5.4 #267 + +## [0.9.2] ### Added -- Support for [PKCE](https://tools.ietf.org/html/rfc7636). Currently, the supported methods are 'plain' and 'S256'. +* Support for [PKCE](https://tools.ietf.org/html/rfc7636). Currently, the supported methods are 'plain' and 'S256'. -## [0.9.1] - 2020-08-27 +## [0.9.1] ### Added -- Add support for MS Azure Active Directory B2C user flows +* Add support for MS Azure Active Directory B2C user flows ### Changed -- Fix at_hash verification #200 -- Getters for public parameters #204 -- Removed client ID query parameter when making a token request using Basic Auth -- Use of `random_bytes()` for token generation instead of `uniqid()`; polyfill for PHP < 7.0 provided. +* Fix at_hash verification #200 +* Getters for public parameters #204 +* Removed client ID query parameter when making a token request using Basic Auth +* Use of `random_bytes()` for token generation instead of `uniqid()`; polyfill for PHP < 7.0 provided. ### Removed -- Removed explicit content-length header - caused issues with proxy servers +* Removed explicit content-length header - caused issues with proxy servers + -## [0.9.0] - 2020-03-09 +## [0.9.0] ### Added -- php 7.4 deprecates array_key_exists on objects, use property_exists in getVerifiedClaims and requestUserInfo -- Adding a header to indicate JSON as the return type for userinfo endpoint #151 -- ~Updated OpenIDConnectClient to conditionally verify nonce #146~ -- Add possibility to change enc_type parameter for http_build_query #155 -- Adding OAuth 2.0 Token Introspection #156 -- Add optional parameters clientId/clientSecret for introspection #157 & #158 -- Adding OAuth 2.0 Token Revocation #160 -- Adding issuer validator #145 -- Adding signing algorithm PS256 #180 -- Check http status of request user info #186 -- URL encode clientId and clientSecret when using basic authentication, according to https://tools.ietf.org/html/rfc6749#section-2.3.1 #192 -- Adjust PHPDoc to state that null is also allowed #193 +* php 7.4 deprecates array_key_exists on objects, use property_exists in getVerifiedClaims and requestUserInfo +* Adding a header to indicate JSON as the return type for userinfo endpoint #151 +* ~Updated OpenIDConnectClient to conditionally verify nonce #146~ +* Add possibility to change enc_type parameter for http_build_query #155 +* Adding OAuth 2.0 Token Introspection #156 +* Add optional parameters clientId/clientSecret for introspection #157 & #158 +* Adding OAuth 2.0 Token Revocation #160 +* Adding issuer validator #145 +* Adding signing algorithm PS256 #180 +* Check http status of request user info #186 +* URL encode clientId and clientSecret when using basic authentication, according to https://tools.ietf.org/html/rfc6749#section-2.3.1 #192 +* Adjust PHPDoc to state that null is also allowed #193 ### Changed -- Bugfix/code cleanup #152 -- Cleanup PHPDoc #46e5b59 -- Replace unnecessary double quotes with single quotes #2a76b57 -- Use original function names instead of aliases #1f37892 -- Remove unnecessary default values #5ab801e -- Explicit declare field $redirectURL #9187c0b -- Remove unused code #1e65384 -- Fix indent #e9cdf56 -- Cleanup conditional code flow for better readability #107f3fb -- Added strict type comparisons #167 -- Bugfix: required `openid` scope was omitted when additional scopes were registered using `addScope` method. This resulted in failing OpenID process. - -## [0.8.0] - 2019-01-02 +* Bugfix/code cleanup #152 + * Cleanup PHPDoc #46e5b59 + * Replace unnecessary double quotes with single quotes #2a76b57 + * Use original function names instead of aliases #1f37892 + * Remove unnecessary default values #5ab801e + * Explicit declare field $redirectURL #9187c0b + * Remove unused code #1e65384 + * Fix indent #e9cdf56 + * Cleanup conditional code flow for better readability #107f3fb + * Added strict type comparisons #167 +* Bugfix: required `openid` scope was omitted when additional scopes were registered using `addScope` method. This resulted in failing OpenID process. + +## [0.8.0] ### Added -- Fix `verifyJWTsignature()`: verify JWT to prevent php errors and warnings on invalid token +* Fix `verifyJWTsignature()`: verify JWT to prevent php errors and warnings on invalid token ### Changed -- Decouple session manipulation, it's allow use of other session libraries #134 -- Broaden version requirements of the phpseclib/phpseclib package. #144 +* Decouple session manipulation, it's allow use of other session libraries #134 +* Broaden version requirements of the phpseclib/phpseclib package. #144 -## [0.7.0] - 2018-10-15 +## [0.7.0] ### Added -- Add "license" field to composer.json #138 -- Ensure key_alg is set when getting key #139 -- Add option to send additional registration parameters like post_logout_redirect_uris. #140 +* Add "license" field to composer.json #138 +* Ensure key_alg is set when getting key #139 +* Add option to send additional registration parameters like post_logout_redirect_uris. #140 ### Changed -- disabled autoload for Crypt_RSA + make refreshToken() method tolerant for errors #137 +* disabled autoload for Crypt_RSA + make refreshToken() method tolerant for errors #137 -## [0.6.0] - 2018-07-17 +### Removed +* + +## [0.6.0] ### Added -- Added five minutes leeway due to clock skew between openidconnect server and client. -- Fix save access_token from request in implicit flow authentication #129 -- `verifyJWTsignature()` method private -> public #126 -- Support for providers where provider/login URL is not the same as the issuer URL. #125 -- Support for providers that has a different login URL from the issuer URL, for instance Azure Active Directory. Here, the provider URL is on the format: https://login.windows.net/(tenant-id), while the issuer claim actually is on the format: https://sts.windows.net/(tenant-id). +* Added five minutes leeway due to clock skew between openidconnect server and client. +* Fix save access_token from request in implicit flow authentication #129 +* `verifyJWTsignature()` method private -> public #126 +* Support for providers where provider/login URL is not the same as the issuer URL. #125 +* Support for providers that has a different login URL from the issuer URL, for instance Azure Active Directory. Here, the provider URL is on the format: https://login.windows.net/(tenant-id), while the issuer claim actually is on the format: https://sts.windows.net/(tenant-id). ### Changed -- refreshToken method update #124 +* refreshToken method update #124 -## [0.5.0] - 2018-04-09 +### Removed +* -### Added -- Implement Azure AD B2C Implicit Workflow +## [0.5.0] +## Added +* Implement Azure AD B2C Implicit Workflow -## [0.4.1] - 2018-02-16 +## [0.4.1] +## Changed +* Documentation updates for include path. -### Changed -- Documentation updates for include path. +## [0.4] +### Added +* Timeout is configurable via setTimeout method. This addresses issue #94. +* Add the ability to authenticate using the Resource Owner flow (with or without the Client ID and ClientSecret). This addresses issue #98 +* Add support for HS256, HS512 and HS384 signatures +* Removed unused calls to $this->getProviderConfigValue("token_endpoint_… -## [0.4.0] - 2018-02-15 +### Changed -### Added -- Timeout is configurable via setTimeout method. This addresses issue #94. -- Add the ability to authenticate using the Resource Owner flow (with or without the Client ID and ClientSecret). This addresses issue #98 -- Add support for HS256, HS512 and HS384 signatures -- Removed unused calls to $this->getProviderConfigValue("token_endpoint_… +### Removed diff --git a/vendor/jumbojett/openid-connect-php/README.md b/vendor/jumbojett/openid-connect-php/README.md index 79318e5..a44b8cb 100644 --- a/vendor/jumbojett/openid-connect-php/README.md +++ b/vendor/jumbojett/openid-connect-php/README.md @@ -152,7 +152,7 @@ ensure your RP performs 'single sign out' for the user even if they didn't have device, but still had an active session there. Either the sid or the sub may be accessible from the logout token sent from the OP. You can use either -`getSidFromBackChannel()` or `getSubjectFromBackChannel()` to retrieve them if it is helpful to match them to a session +`getSidFromBackChannel()` or `getSubFromBackChannel()` to retrieve them if it is helpful to match them to a session in order to destroy it. The below ensures the use of this library to ensure validation of the back-channel logout token, but is afterward diff --git a/vendor/jumbojett/openid-connect-php/composer.json b/vendor/jumbojett/openid-connect-php/composer.json index 3fa6d23..6d218cc 100644 --- a/vendor/jumbojett/openid-connect-php/composer.json +++ b/vendor/jumbojett/openid-connect-php/composer.json @@ -3,13 +3,14 @@ "description": "Bare-bones OpenID Connect client", "license": "Apache-2.0", "require": { - "php": ">=7.0", + "php": ">=5.4", + "phpseclib/phpseclib" : "~2.0 || ^3.0", "ext-json": "*", "ext-curl": "*", - "phpseclib/phpseclib": "~3.0" + "paragonie/random_compat": ">=2" }, "require-dev": { - "roave/security-advisories": "dev-latest", + "roave/security-advisories": "dev-master", "yoast/phpunit-polyfills": "^1.0" }, "archive" : { diff --git a/vendor/jumbojett/openid-connect-php/src/OpenIDConnectClient.php b/vendor/jumbojett/openid-connect-php/src/OpenIDConnectClient.php index 6aa80b1..bac366c 100644 --- a/vendor/jumbojett/openid-connect-php/src/OpenIDConnectClient.php +++ b/vendor/jumbojett/openid-connect-php/src/OpenIDConnectClient.php @@ -22,16 +22,18 @@ namespace Jumbojett; +/** + * + * JWT signature verification support by Jonathan Reed <[email protected]> + * Licensed under the same license as the rest of this file. + * + * phpseclib is required to validate the signatures of some tokens. + * It can be downloaded from: http://phpseclib.sourceforge.net/ + */ -use Error; -use Exception; -use phpseclib3\Crypt\PublicKeyLoader; -use phpseclib3\Crypt\RSA; -use phpseclib3\Math\BigInteger; -use stdClass; -use function bin2hex; -use function is_object; -use function random_bytes; +if (!class_exists('\phpseclib3\Crypt\RSA') && !class_exists('\phpseclib\Crypt\RSA') && !class_exists('Crypt_RSA')) { + user_error('Unable to find phpseclib Crypt/RSA.php. Ensure phpseclib is installed and in include_path before you include this file'); +} /** * A wrapper around base64_decode which decodes Base64URL-encoded data, @@ -39,7 +41,7 @@ use function random_bytes; * @param string $base64url * @return bool|string */ -function base64url_decode(string $base64url) { +function base64url_decode($base64url) { return base64_decode(b64url2b64($base64url)); } @@ -51,8 +53,7 @@ function base64url_decode(string $base64url) { * @param string $base64url * @return string */ -function b64url2b64(string $base64url): string -{ +function b64url2b64($base64url) { // "Shouldn't" be necessary, but why not $padding = strlen($base64url) % 4; if ($padding > 0) { @@ -65,8 +66,19 @@ function b64url2b64(string $base64url): string /** * OpenIDConnect Exception Class */ -class OpenIDConnectClientException extends Exception +class OpenIDConnectClientException extends \Exception { + +} + +/** + * Require the CURL and JSON PHP extensions to be installed + */ +if (!function_exists('curl_init')) { + throw new OpenIDConnectClientException('OpenIDConnect needs the CURL PHP extension.'); +} +if (!function_exists('json_decode')) { + throw new OpenIDConnectClientException('OpenIDConnect needs the JSON PHP extension.'); } /** @@ -133,7 +145,7 @@ class OpenIDConnectClient protected $idToken; /** - * @var object stores the token response + * @var string stores the token response */ private $tokenResponse; @@ -148,14 +160,14 @@ class OpenIDConnectClient private $responseCode; /** - * @var string|null Content type from the server + * @var array holds response types */ - private $responseContentType; + private $responseTypes = []; /** - * @var array holds response types + * @var array holds a cache of info returned from the user info endpoint */ - private $responseTypes = []; + private $userInfo = []; /** * @var array holds authentication parameters @@ -173,7 +185,7 @@ class OpenIDConnectClient private $wellKnown = false; /** - * @var mixed holds well-known openid configuration parameters, like policy for MS Azure AD B2C User Flow + * @var mixed holds well-known opendid configuration parameters, like policy for MS Azure AD B2C User Flow * @see https://docs.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview */ private $wellKnownConfigParameters = []; @@ -194,7 +206,7 @@ class OpenIDConnectClient private $additionalJwks = []; /** - * @var object holds verified jwt claims + * @var array holds verified jwt claims */ protected $verifiedClaims = []; @@ -255,12 +267,13 @@ class OpenIDConnectClient private $token_endpoint_auth_methods_supported = ['client_secret_basic']; /** - * @param string|null $provider_url optional - * @param string|null $client_id optional - * @param string|null $client_secret optional - * @param string|null $issuer + * @param $provider_url string optional + * + * @param $client_id string optional + * @param $client_secret string optional + * @param null $issuer */ - public function __construct(string $provider_url = null, string $client_id = null, string $client_secret = null, string $issuer = null) { + public function __construct($provider_url = null, $client_id = null, $client_secret = null, $issuer = null) { $this->setProviderURL($provider_url); if ($issuer === null) { $this->setIssuer($provider_url); @@ -297,8 +310,8 @@ class OpenIDConnectClient * @return bool * @throws OpenIDConnectClientException */ - public function authenticate(): bool - { + public function authenticate() { + // Do a preemptive check to see if the provider has thrown an error from a previous redirect if (isset($_REQUEST['error'])) { $desc = isset($_REQUEST['error_description']) ? ' Description: ' . $_REQUEST['error_description'] : ''; @@ -320,7 +333,7 @@ class OpenIDConnectClient } // Do an OpenID Connect session check - if (!isset($_REQUEST['state']) || ($_REQUEST['state'] !== $this->getState())) { + if ($_REQUEST['state'] !== $this->getState()) { throw new OpenIDConnectClientException('Unable to determine state'); } @@ -331,26 +344,28 @@ class OpenIDConnectClient throw new OpenIDConnectClientException('User did not authorize openid scope.'); } - $id_token = $token_json->id_token; - $idTokenHeaders = $this->decodeJWT($id_token); - if (isset($idTokenHeaders->enc)) { - // Handle JWE - $id_token = $this->handleJweResponse($id_token); - } - - $claims = $this->decodeJWT($id_token, 1); + $claims = $this->decodeJWT($token_json->id_token, 1); // Verify the signature - $this->verifySignatures($id_token); + if ($this->canVerifySignatures()) { + if (!$this->getProviderConfigValue('jwks_uri')) { + throw new OpenIDConnectClientException ('Unable to verify signature due to no jwks_uri being defined'); + } + if (!$this->verifyJWTsignature($token_json->id_token)) { + throw new OpenIDConnectClientException ('Unable to verify signature'); + } + } else { + user_error('Warning: JWT signature verification unavailable.'); + } // Save the id token - $this->idToken = $id_token; + $this->idToken = $token_json->id_token; // Save the access token $this->accessToken = $token_json->access_token; // If this is a valid claim - if ($this->verifyJWTClaims($claims, $token_json->access_token)) { + if ($this->verifyJWTclaims($claims, $token_json->access_token)) { // Clean up the session a little $this->unsetNonce(); @@ -377,10 +392,13 @@ class OpenIDConnectClient // if we have no code but an id_token use that $id_token = $_REQUEST['id_token']; - $accessToken = $_REQUEST['access_token'] ?? null; + $accessToken = null; + if (isset($_REQUEST['access_token'])) { + $accessToken = $_REQUEST['access_token']; + } // Do an OpenID Connect session check - if (!isset($_REQUEST['state']) || ($_REQUEST['state'] !== $this->getState())) { + if ($_REQUEST['state'] !== $this->getState()) { throw new OpenIDConnectClientException('Unable to determine state'); } @@ -390,13 +408,22 @@ class OpenIDConnectClient $claims = $this->decodeJWT($id_token, 1); // Verify the signature - $this->verifySignatures($id_token); + if ($this->canVerifySignatures()) { + if (!$this->getProviderConfigValue('jwks_uri')) { + throw new OpenIDConnectClientException ('Unable to verify signature due to no jwks_uri being defined'); + } + if (!$this->verifyJWTsignature($id_token)) { + throw new OpenIDConnectClientException ('Unable to verify signature'); + } + } else { + user_error('Warning: JWT signature verification unavailable.'); + } // Save the id token $this->idToken = $id_token; // If this is a valid claim - if ($this->verifyJWTClaims($claims, $accessToken)) { + if ($this->verifyJWTclaims($claims, $accessToken)) { // Clean up the session a little $this->unsetNonce(); @@ -433,9 +460,10 @@ class OpenIDConnectClient * * @throws OpenIDConnectClientException */ - public function signOut(string $idToken, $redirect) { - $sign_out_endpoint = $this->getProviderConfigValue('end_session_endpoint'); + public function signOut($idToken, $redirect) { + $signout_endpoint = $this->getProviderConfigValue('end_session_endpoint'); + $signout_params = null; if($redirect === null){ $signout_params = ['id_token_hint' => $idToken]; } @@ -445,8 +473,8 @@ class OpenIDConnectClient 'post_logout_redirect_uri' => $redirect]; } - $sign_out_endpoint .= (strpos($sign_out_endpoint, '?') === false ? '?' : '&') . http_build_query( $signout_params, '', '&', $this->encType); - $this->redirect($sign_out_endpoint); + $signout_endpoint .= (strpos($signout_endpoint, '?') === false ? '?' : '&') . http_build_query( $signout_params, '', '&', $this->encType); + $this->redirect($signout_endpoint); } @@ -461,7 +489,7 @@ class OpenIDConnectClient * @return bool * @throws OpenIDConnectClientException */ - public function verifyLogoutToken(): bool + public function verifyLogoutToken() { if (isset($_REQUEST['logout_token'])) { $logout_token = $_REQUEST['logout_token']; @@ -469,11 +497,16 @@ class OpenIDConnectClient $claims = $this->decodeJWT($logout_token, 1); // Verify the signature - if (!$this->getProviderConfigValue('jwks_uri')) { - throw new OpenIDConnectClientException('Back-channel logout: Unable to verify signature due to no jwks_uri being defined'); + if ($this->canVerifySignatures()) { + if (!$this->getProviderConfigValue('jwks_uri')) { + throw new OpenIDConnectClientException('Back-channel logout: Unable to verify signature due to no jwks_uri being defined'); + } + if (!$this->verifyJWTsignature($logout_token)) { + throw new OpenIDConnectClientException('Back-channel logout: Unable to verify JWT signature'); + } } - if (!$this->verifyJWTSignature($logout_token)) { - throw new OpenIDConnectClientException('Back-channel logout: Unable to verify JWT signature'); + else { + user_error('Warning: JWT signature verification unavailable'); } // Verify Logout Token Claims @@ -496,7 +529,7 @@ class OpenIDConnectClient * @return bool * @throws OpenIDConnectClientException */ - public function verifyLogoutTokenClaims($claims): bool + public function verifyLogoutTokenClaims($claims) { // Verify that the Logout Token doesn't contain a nonce Claim. if (isset($claims->nonce)) { @@ -537,9 +570,7 @@ class OpenIDConnectClient return false; } // Validate the aud - $auds = $claims->aud; - $auds = is_array( $auds ) ? $auds : [ $auds ]; - if (!in_array($this->clientID, $auds, true)) { + if ((!$claims->aud === $this->clientID) || (!in_array($this->clientID, $claims->aud, true))) { return false; } // Validate the iat. At this point we can return true if it is ok @@ -553,25 +584,28 @@ class OpenIDConnectClient /** * @param array $scope - example: openid, given_name, etc... */ - public function addScope(array $scope) { - $this->scopes = array_merge($this->scopes, $scope); + public function addScope($scope) { + $this->scopes = array_merge($this->scopes, (array)$scope); } /** * @param array $param - example: prompt=login */ - public function addAuthParam(array $param) { - $this->authParams = array_merge($this->authParams, $param); + public function addAuthParam($param) { + $this->authParams = array_merge($this->authParams, (array)$param); } /** * @param array $param - example: post_logout_redirect_uris=[http://example.com/successful-logout] */ - public function addRegistrationParam(array $param) { - $this->registrationParams = array_merge($this->registrationParams, $param); + public function addRegistrationParam($param) { + $this->registrationParams = array_merge($this->registrationParams, (array)$param); } - public function setTokenEndpointAuthMethodsSupported(array $token_endpoint_auth_methods_supported) + /** + * @param array $token_endpoint_auth_methods_supported + */ + public function setTokenEndpointAuthMethodsSupported($token_endpoint_auth_methods_supported) { $this->token_endpoint_auth_methods_supported = $token_endpoint_auth_methods_supported; } @@ -584,16 +618,16 @@ class OpenIDConnectClient } /** - * Gets anything that we need configuration wise including endpoints, and other values + * Get's anything that we need configuration wise including endpoints, and other values * * @param string $param - * @param string|string[]|bool|null $default optional - * @return string|string[]|bool - * + * @param string $default optional * @throws OpenIDConnectClientException + * @return string|array + * */ - protected function getProviderConfigValue(string $param, $default = null) - { + protected function getProviderConfigValue($param, $default = null) { + // If the configuration value is not available, attempt to fetch it from a well known config endpoint // This is also known as auto "discovery" if (!isset($this->providerConfig[$param])) { @@ -604,16 +638,15 @@ class OpenIDConnectClient } /** - * Gets anything that we need configuration wise including endpoints, and other values + * Get's anything that we need configuration wise including endpoints, and other values * * @param string $param - * @param string|string[]|bool|null $default optional - * @return string|string[]|bool - * + * @param string $default optional * @throws OpenIDConnectClientException + * @return string + * */ - protected function getWellKnownConfigValue(string $param, $default = null) - { + private function getWellKnownConfigValue($param, $default = null) { // If the configuration value is not available, attempt to fetch it from a well known config endpoint // This is also known as auto "discovery" @@ -622,10 +655,13 @@ class OpenIDConnectClient if (count($this->wellKnownConfigParameters) > 0){ $well_known_config_url .= '?' . http_build_query($this->wellKnownConfigParameters) ; } - $this->wellKnown = json_decode($this->fetchURL($well_known_config_url), false); + $this->wellKnown = json_decode($this->fetchURL($well_known_config_url)); } - $value = $this->wellKnown->{$param} ?? false; + $value = false; + if(isset($this->wellKnown->{$param})){ + $value = $this->wellKnown->{$param}; + } if ($value) { return $value; @@ -636,11 +672,14 @@ class OpenIDConnectClient return $default; } - throw new OpenIDConnectClientException("The provider $param could not be fetched. Make sure your provider has a well known configuration available."); + throw new OpenIDConnectClientException("The provider {$param} could not be fetched. Make sure your provider has a well known configuration available."); } /** - * Set optional parameters for .well-known/openid-configuration + * Set optionnal parameters for .well-known/openid-configuration + * + * @param string $param + * */ public function setWellKnownConfigParameters(array $params = []){ $this->wellKnownConfigParameters=$params; @@ -650,7 +689,7 @@ class OpenIDConnectClient /** * @param string $url Sets redirect URL for auth flow */ - public function setRedirectURL(string $url) { + public function setRedirectURL($url) { if (parse_url($url,PHP_URL_HOST) !== false) { $this->redirectURL = $url; } @@ -661,8 +700,8 @@ class OpenIDConnectClient * * @return string */ - public function getRedirectURL(): string - { + public function getRedirectURL() { + // If the redirect URL has been set then return it. if (property_exists($this, 'redirectURL') && $this->redirectURL) { return $this->redirectURL; @@ -694,9 +733,9 @@ class OpenIDConnectClient } if (isset($_SERVER['HTTP_X_FORWARDED_PORT'])) { - $port = (int)$_SERVER['HTTP_X_FORWARDED_PORT']; + $port = intval($_SERVER['HTTP_X_FORWARDED_PORT']); } elseif (isset($_SERVER['SERVER_PORT'])) { - $port = $_SERVER['SERVER_PORT']; + $port = intval($_SERVER['SERVER_PORT']); } elseif ($protocol === 'https') { $port = 443; } else { @@ -725,10 +764,11 @@ class OpenIDConnectClient * @return string * @throws OpenIDConnectClientException */ - protected function generateRandString(): string - { + protected function generateRandString() { + // Error and Exception need to be catched in this order, see https://github.com/paragonie/random_compat/blob/master/README.md + // random_compat polyfill library should be removed if support for PHP versions < 7 is dropped try { - return bin2hex(random_bytes(16)); + return \bin2hex(\random_bytes(16)); } catch (Error $e) { throw new OpenIDConnectClientException('Random token generation failed.'); } catch (Exception $e) { @@ -740,7 +780,7 @@ class OpenIDConnectClient * Start Here * @return void * @throws OpenIDConnectClientException - * @throws Exception + * @throws \Exception */ private function requestAuthorization() { @@ -817,7 +857,7 @@ class OpenIDConnectClient // Convert token params to string format $post_params = http_build_query($post_data, '', '&', $this->encType); - return json_decode($this->fetchURL($token_endpoint, $post_params, $headers), false); + return json_decode($this->fetchURL($token_endpoint, $post_params, $headers)); } /** @@ -828,7 +868,7 @@ class OpenIDConnectClient * @return mixed * @throws OpenIDConnectClientException */ - public function requestResourceOwnerToken(bool $bClientAuth = false) { + public function requestResourceOwnerToken($bClientAuth = FALSE) { $token_endpoint = $this->getProviderConfigValue('token_endpoint'); $headers = []; @@ -856,7 +896,7 @@ class OpenIDConnectClient // Convert token params to string format $post_params = http_build_query($post_data, '', '&', $this->encType); - return json_decode($this->fetchURL($token_endpoint, $post_params, $headers), false); + return json_decode($this->fetchURL($token_endpoint, $post_params, $headers)); } @@ -868,7 +908,7 @@ class OpenIDConnectClient * @return mixed * @throws OpenIDConnectClientException */ - protected function requestTokens(string $code, array $headers = []) { + protected function requestTokens($code, $headers = array()) { $token_endpoint = $this->getProviderConfigValue('token_endpoint'); $token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']); @@ -886,10 +926,11 @@ class OpenIDConnectClient # Consider Basic authentication if provider config is set this way if ($this->supportsAuthMethod('client_secret_basic', $token_endpoint_auth_methods_supported)) { $authorizationHeader = 'Authorization: Basic ' . base64_encode(urlencode($this->clientID) . ':' . urlencode($this->clientSecret)); - unset($token_params['client_secret'], $token_params['client_id']); + unset($token_params['client_secret']); + unset($token_params['client_id']); } - // When there is a private key jwt generator, and it is supported then use it as client authentication + // When there is a private key jwt generator and it is supported then use it as client authentication if ($this->privateKeyJwtGenerator !== null && $this->supportsAuthMethod('private_key_jwt', $token_endpoint_auth_methods_supported)) { $token_params['client_assertion_type'] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'; $token_params['client_assertion'] = $this->privateKeyJwtGenerator->__invoke($token_endpoint); @@ -904,7 +945,7 @@ class OpenIDConnectClient else{ $client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('token_endpoint')); } - + $token_params['client_assertion_type'] = $client_assertion_type; $token_params['client_assertion'] = $client_assertion; unset($token_params['client_secret']); @@ -931,7 +972,7 @@ class OpenIDConnectClient $headers[] = $authorizationHeader; } - $this->tokenResponse = json_decode($this->fetchURL($token_endpoint, $token_params, $headers), false); + $this->tokenResponse = json_decode($this->fetchURL($token_endpoint, $token_params, $headers)); return $this->tokenResponse; } @@ -946,7 +987,7 @@ class OpenIDConnectClient * @return mixed * @throws OpenIDConnectClientException */ - public function requestTokenExchange(string $subjectToken, string $subjectTokenType, string $audience = '') { + public function requestTokenExchange($subjectToken, $subjectTokenType, $audience = '') { $token_endpoint = $this->getProviderConfigValue('token_endpoint'); $token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']); $headers = []; @@ -968,13 +1009,14 @@ class OpenIDConnectClient # Consider Basic authentication if provider config is set this way if ($this->supportsAuthMethod('client_secret_basic', $token_endpoint_auth_methods_supported)) { $headers = ['Authorization: Basic ' . base64_encode(urlencode($this->clientID) . ':' . urlencode($this->clientSecret))]; - unset($post_data['client_secret'], $post_data['client_id']); + unset($post_data['client_secret']); + unset($post_data['client_id']); } // Convert token params to string format $post_params = http_build_query($post_data, null, '&', $this->encType); - return json_decode($this->fetchURL($token_endpoint, $post_params, $headers), false); + return json_decode($this->fetchURL($token_endpoint, $post_params, $headers)); } @@ -985,7 +1027,7 @@ class OpenIDConnectClient * @return mixed * @throws OpenIDConnectClientException */ - public function refreshToken(string $refresh_token) { + public function refreshToken($refresh_token) { $token_endpoint = $this->getProviderConfigValue('token_endpoint'); $token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']); @@ -1004,13 +1046,14 @@ class OpenIDConnectClient # Consider Basic authentication if provider config is set this way if ($this->supportsAuthMethod('client_secret_basic', $token_endpoint_auth_methods_supported)) { $headers = ['Authorization: Basic ' . base64_encode(urlencode($this->clientID) . ':' . urlencode($this->clientSecret))]; - unset($token_params['client_secret'], $token_params['client_id']); + unset($token_params['client_secret']); + unset($token_params['client_id']); } if ($this->supportsAuthMethod('client_secret_jwt', $token_endpoint_auth_methods_supported)) { $client_assertion_type = $this->getProviderConfigValue('client_assertion_type'); $client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('token_endpoint')); - + $token_params["grant_type"] = "urn:ietf:params:oauth:grant-type:token-exchange"; $token_params["subject_token"] = $refresh_token; $token_params["audience"] = $this->clientID; @@ -1018,13 +1061,14 @@ class OpenIDConnectClient $token_params["requested_token_type"] = "urn:ietf:params:oauth:token-type:access_token"; $token_params['client_assertion_type']=$client_assertion_type; $token_params['client_assertion'] = $client_assertion; - - unset($token_params['client_secret'], $token_params['client_id']); + + unset($token_params['client_secret']); + unset($token_params['client_id']); } // Convert token params to string format $token_params = http_build_query($token_params, '', '&', $this->encType); - $json = json_decode($this->fetchURL($token_endpoint, $token_params, $headers), false); + $json = json_decode($this->fetchURL($token_endpoint, $token_params, $headers)); if (isset($json->access_token)) { $this->accessToken = $json->access_token; @@ -1038,16 +1082,21 @@ class OpenIDConnectClient } /** + * @param array $keys + * @param array $header * @throws OpenIDConnectClientException + * @return object */ - private function getKeyForHeader(array $keys, stdClass $header) { + private function getKeyForHeader($keys, $header) { foreach ($keys as $key) { if ($key->kty === 'RSA') { if (!isset($header->kid) || $key->kid === $header->kid) { return $key; } - } else if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { - return $key; + } else { + if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { + return $key; + } } } if ($this->additionalJwks) { @@ -1056,8 +1105,10 @@ class OpenIDConnectClient if (!isset($header->kid) || $key->kid === $header->kid) { return $key; } - } else if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { - return $key; + } else { + if (isset($key->alg) && $key->alg === $header->alg && $key->kid === $header->kid) { + return $key; + } } } } @@ -1068,43 +1119,94 @@ class OpenIDConnectClient throw new OpenIDConnectClientException('Unable to find a key for RSA'); } + /** + * @param string $hashtype + * @param object $key + * @param $payload + * @param $signature + * @param $signatureType + * @return bool * @throws OpenIDConnectClientException */ - private function verifyRSAJWTSignature(string $hashType, stdClass $key, $payload, $signature, $signatureType): bool - { + private function verifyRSAJWTsignature($hashtype, $key, $payload, $signature, $signatureType) { + if (!class_exists('\phpseclib3\Crypt\RSA') && !class_exists('\phpseclib\Crypt\RSA') && !class_exists('Crypt_RSA')) { + throw new OpenIDConnectClientException('Crypt_RSA support unavailable.'); + } if (!(property_exists($key, 'n') && property_exists($key, 'e'))) { throw new OpenIDConnectClientException('Malformed key object'); } - $key = RSA::load([ - 'publicExponent' => new BigInteger(base64_decode(b64url2b64($key->e)), 256), - 'modulus' => new BigInteger(base64_decode(b64url2b64($key->n)), 256), - 'isPublicKey' => true, - ]) - ->withHash($hashType); - if ($signatureType === 'PSS') { - $key = $key->withMGFHash($hashType) - ->withPadding(RSA::SIGNATURE_PSS); + /* We already have base64url-encoded data, so re-encode it as + regular base64 and use the XML key format for simplicity. + */ + $public_key_xml = "<RSAKeyValue>\r\n". + ' <Modulus>' . b64url2b64($key->n) . "</Modulus>\r\n" . + ' <Exponent>' . b64url2b64($key->e) . "</Exponent>\r\n" . + '</RSAKeyValue>'; + if (class_exists('\phpseclib3\Crypt\RSA', false)) { + $key = \phpseclib3\Crypt\PublicKeyLoader::load($public_key_xml) + ->withHash($hashtype); + if ($signatureType === 'PSS') { + $key = $key->withMGFHash($hashtype) + ->withPadding(\phpseclib3\Crypt\RSA::SIGNATURE_PSS); + } else { + $key = $key->withPadding(\phpseclib3\Crypt\RSA::SIGNATURE_PKCS1); + } + return $key->verify($payload, $signature); + } elseif (class_exists('Crypt_RSA', false)) { + $rsa = new Crypt_RSA(); + $rsa->setHash($hashtype); + if ($signatureType === 'PSS') { + $rsa->setMGFHash($hashtype); + } + $rsa->loadKey($public_key_xml, Crypt_RSA::PUBLIC_FORMAT_XML); + $rsa->setSignatureMode($signatureType === 'PSS' ? Crypt_RSA::SIGNATURE_PSS : Crypt_RSA::SIGNATURE_PKCS1); + return $rsa->verify($payload, $signature); } else { - $key = $key->withPadding(RSA::SIGNATURE_PKCS1); + $rsa = new \phpseclib\Crypt\RSA(); + $rsa->setHash($hashtype); + if ($signatureType === 'PSS') { + $rsa->setMGFHash($hashtype); + } + $rsa->loadKey($public_key_xml, \phpseclib\Crypt\RSA::PUBLIC_FORMAT_XML); + $rsa->setSignatureMode($signatureType === 'PSS' ? \phpseclib\Crypt\RSA::SIGNATURE_PSS : \phpseclib\Crypt\RSA::SIGNATURE_PKCS1); + return $rsa->verify($payload, $signature); } - return $key->verify($payload, $signature); } - private function verifyHMACJWTSignature(string $hashType, string $key, string $payload, string $signature): bool + /** + * @param string $hashtype + * @param object $key + * @param $payload + * @param $signature + * @return bool + * @throws OpenIDConnectClientException + */ + private function verifyHMACJWTsignature($hashtype, $key, $payload, $signature) { - $expected = hash_hmac($hashType, $payload, $key, true); - return hash_equals($signature, $expected); + if (!function_exists('hash_hmac')) { + throw new OpenIDConnectClientException('hash_hmac support unavailable.'); + } + + $expected=hash_hmac($hashtype, $payload, $key, true); + + if (function_exists('hash_equals')) { + return hash_equals($signature, $expected); + } + + return self::hashEquals($signature, $expected); } /** * @param string $jwt encoded JWT - * @return bool * @throws OpenIDConnectClientException + * @return bool */ - public function verifyJWTSignature(string $jwt): bool - { + public function verifyJWTsignature($jwt) { + if (!\is_string($jwt)) { + throw new OpenIDConnectClientException('Error token is not a string'); + } $parts = explode('.', $jwt); if (!isset($parts[0])) { throw new OpenIDConnectClientException('Error missing part 0 in token'); @@ -1113,8 +1215,8 @@ class OpenIDConnectClient if (false === $signature || '' === $signature) { throw new OpenIDConnectClientException('Error decoding signature from token'); } - $header = json_decode(base64url_decode($parts[0]), false); - if (!is_object($header)) { + $header = json_decode(base64url_decode($parts[0])); + if (null === $header || !\is_object($header)) { throw new OpenIDConnectClientException('Error decoding JSON from token header'); } if (!isset($header->alg)) { @@ -1128,28 +1230,28 @@ class OpenIDConnectClient case 'PS512': case 'RS384': case 'RS512': - $hashType = 'sha' . substr($header->alg, 2); + $hashtype = 'sha' . substr($header->alg, 2); $signatureType = $header->alg === 'PS256' || $header->alg === 'PS512' ? 'PSS' : ''; if (isset($header->jwk)) { $jwk = $header->jwk; $this->verifyJWKHeader($jwk); } else { - $jwks = json_decode($this->fetchURL($this->getProviderConfigValue('jwks_uri')), false); + $jwks = json_decode($this->fetchURL($this->getProviderConfigValue('jwks_uri'))); if ($jwks === NULL) { throw new OpenIDConnectClientException('Error decoding JSON from jwks_uri'); } $jwk = $this->getKeyForHeader($jwks->keys, $header); } - $verified = $this->verifyRSAJWTSignature($hashType, + $verified = $this->verifyRSAJWTsignature($hashtype, $jwk, $payload, $signature, $signatureType); break; case 'HS256': case 'HS512': case 'HS384': - $hashType = 'SHA' . substr($header->alg, 2); - $verified = $this->verifyHMACJWTSignature($hashType, $this->getClientSecret(), $payload, $signature); + $hashtype = 'SHA' . substr($header->alg, 2); + $verified = $this->verifyHMACJWTsignature($hashtype, $this->getClientSecret(), $payload, $signature); break; default: throw new OpenIDConnectClientException('No support for signature type: ' . $header->alg); @@ -1158,27 +1260,11 @@ class OpenIDConnectClient } /** - * @param string $jwt encoded JWT - * @return void - * @throws OpenIDConnectClientException - */ - public function verifySignatures(string $jwt) - { - if (!$this->getProviderConfigValue('jwks_uri')) { - throw new OpenIDConnectClientException ('Unable to verify signature due to no jwks_uri being defined'); - } - if (!$this->verifyJWTSignature($jwt)) { - throw new OpenIDConnectClientException ('Unable to verify signature'); - } - } - - /** * @param string $iss * @return bool * @throws OpenIDConnectClientException */ - protected function validateIssuer(string $iss): bool - { + protected function validateIssuer($iss) { if ($this->issuerValidator !== null) { return $this->issuerValidator->__invoke($iss); } @@ -1190,11 +1276,9 @@ class OpenIDConnectClient * @param object $claims * @param string|null $accessToken * @return bool - * @throws OpenIDConnectClientException */ - protected function verifyJWTClaims($claims, string $accessToken = null): bool - { - if(isset($claims->at_hash, $accessToken)) { + protected function verifyJWTclaims($claims, $accessToken = null) { + if(isset($claims->at_hash) && isset($accessToken)) { if(isset($this->getIdTokenHeader()->alg) && $this->getIdTokenHeader()->alg !== 'none') { $bit = substr($this->getIdTokenHeader()->alg, 2, 3); } else { @@ -1207,17 +1291,21 @@ class OpenIDConnectClient return (($this->validateIssuer($claims->iss)) && (($claims->aud === $this->clientID) || in_array($this->clientID, $claims->aud, true)) && (!isset($claims->nonce) || $claims->nonce === $this->getNonce()) - && ( !isset($claims->exp) || ((is_int($claims->exp)) && ($claims->exp >= time() - $this->leeway))) - && ( !isset($claims->nbf) || ((is_int($claims->nbf)) && ($claims->nbf <= time() + $this->leeway))) + && ( !isset($claims->exp) || ((gettype($claims->exp) === 'integer') && ($claims->exp >= time() - $this->leeway))) + && ( !isset($claims->nbf) || ((gettype($claims->nbf) === 'integer') && ($claims->nbf <= time() + $this->leeway))) && ( !isset($claims->at_hash) || !isset($accessToken) || $claims->at_hash === $expected_at_hash ) ); } - protected function urlEncode(string $str): string - { + /** + * @param string $str + * @return string + */ + protected function urlEncode($str) { $enc = base64_encode($str); $enc = rtrim($enc, '='); - return strtr($enc, '+/', '-_'); + $enc = strtr($enc, '+/', '-_'); + return $enc; } /** @@ -1225,10 +1313,10 @@ class OpenIDConnectClient * @param int $section the section we would like to decode * @return object */ - protected function decodeJWT(string $jwt, int $section = 0): stdClass { + protected function decodeJWT($jwt, $section = 0) { $parts = explode('.', $jwt); - return json_decode(base64url_decode($parts[$section]), false); + return json_decode(base64url_decode($parts[$section])); } /** @@ -1253,13 +1341,13 @@ class OpenIDConnectClient * locale string The End-User's locale, represented as a BCP47 [RFC5646] language tag. This is typically an ISO 639-1 Alpha-2 [ISO639‑1] language code in lowercase and an ISO 3166-1 Alpha-2 [ISO3166‑1] country code in uppercase, separated by a dash. For example, en-US or fr-CA. As a compatibility note, some implementations have used an underscore as the separator rather than a dash, for example, en_US; Implementations MAY choose to accept this locale syntax as well. * phone_number string The End-User's preferred telephone number. E.164 [E.164] is RECOMMENDED as the format of this Claim. For example, +1 (425) 555-1212 or +56 (2) 687 2400. * address JSON object The End-User's preferred address. The value of the address member is a JSON [RFC4627] structure containing some or all of the members defined in Section 2.4.2.1. - * updated_time string Time the End-User's information was last updated, represented as an RFC 3339 [RFC3339] datetime. For example, 2011-01-03T23:58:42+0000. + * updated_time string Time the End-User's information was last updated, represented as a RFC 3339 [RFC3339] datetime. For example, 2011-01-03T23:58:42+0000. * * @return mixed * * @throws OpenIDConnectClientException */ - public function requestUserInfo(string $attribute = null) { + public function requestUserInfo($attribute = null) { $user_info_endpoint = $this->getProviderConfigValue('userinfo_endpoint'); $schema = 'openid'; @@ -1268,50 +1356,21 @@ class OpenIDConnectClient //The accessToken has to be sent in the Authorization header. // Accept json to indicate response type - $headers = ["Authorization: Bearer $this->accessToken", + $headers = ["Authorization: Bearer {$this->accessToken}", 'Accept: application/json']; - $response = $this->fetchURL($user_info_endpoint,null,$headers); - if ($this->getResponseCode() !== 200) { + $user_json = json_decode($this->fetchURL($user_info_endpoint,null,$headers)); + if ($this->getResponseCode() <> 200) { throw new OpenIDConnectClientException('The communication to retrieve user data has failed with status code '.$this->getResponseCode()); } - - // When we receive application/jwt, the UserInfo Response is signed and/or encrypted. - if ($this->getResponseContentType() === 'application/jwt' ) { - // Check if the response is encrypted - $jwtHeaders = $this->decodeJWT($response); - if (isset($jwtHeaders->enc)) { - // Handle JWE - $jwt = $this->handleJweResponse($response); - } else { - // If the response is not encrypted then it must be signed - $jwt = $response; - } - - // Verify the signature - $this->verifySignatures($jwt); - - // Get claims from JWT - $claims = $this->decodeJWT($jwt, 1); - - // Verify the JWT claims - if (!$this->verifyJWTClaims($claims)) { - throw new OpenIDConnectClientException('Invalid JWT signature'); - } - - $user_json = $claims; - } else { - $user_json = json_decode($response, false); - } - - $userInfo = $user_json; + $this->userInfo = $user_json; if($attribute === null) { - return $userInfo; + return $this->userInfo; } - if (property_exists($userInfo, $attribute)) { - return $userInfo->$attribute; + if (property_exists($this->userInfo, $attribute)) { + return $this->userInfo->$attribute; } return null; @@ -1330,13 +1389,13 @@ class OpenIDConnectClient * aud string Audience * nonce string nonce * iat int Issued At - * auth_time int Authentication time + * auth_time int Authenatication time * oid string Object id * * @return mixed * */ - public function getVerifiedClaims(string $attribute = null) { + public function getVerifiedClaims($attribute = null) { if($attribute === null) { return $this->verifiedClaims; @@ -1352,11 +1411,11 @@ class OpenIDConnectClient /** * @param string $url * @param string | null $post_body string If this is set the post type will be POST - * @param array $headers Extra headers to be sent with the request. Format as 'NameHeader: ValueHeader' - * @return bool|string + * @param array $headers Extra headers to be send with the request. Format as 'NameHeader: ValueHeader' * @throws OpenIDConnectClientException + * @return mixed */ - protected function fetchURL(string $url, string $post_body = null, array $headers = []) { + protected function fetchURL($url, $post_body = null, $headers = []) { // OK cool - then let's create a new cURL resource handle $ch = curl_init(); @@ -1364,7 +1423,7 @@ class OpenIDConnectClient // Determine whether this is a GET or POST if ($post_body !== null) { // curl_setopt($ch, CURLOPT_POST, 1); - // Allows to keep the POST method even after redirect + // Alows to keep the POST method even after redirect curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body); @@ -1372,16 +1431,14 @@ class OpenIDConnectClient $content_type = 'application/x-www-form-urlencoded'; // Determine if this is a JSON payload and add the appropriate content type - if (is_object(json_decode($post_body, false))) { + if (is_object(json_decode($post_body))) { $content_type = 'application/json'; } // Add POST-specific headers - $headers[] = "Content-Type: $content_type"; - } + $headers[] = "Content-Type: {$content_type}"; - // Set the User-Agent - curl_setopt($ch, CURLOPT_USERAGENT, $this->getUserAgent()); + } // If we set some headers include them if(count($headers) > 0) { @@ -1433,7 +1490,6 @@ class OpenIDConnectClient // HTTP Response code from server may be required from subclass $info = curl_getinfo($ch); $this->responseCode = $info['http_code']; - $this->responseContentType = $info['content_type']; if ($output === false) { throw new OpenIDConnectClientException('Curl error: (' . curl_errno($ch) . ') ' . curl_error($ch)); @@ -1446,18 +1502,20 @@ class OpenIDConnectClient } /** + * @param bool $appendSlash + * @return string * @throws OpenIDConnectClientException */ - public function getWellKnownIssuer(bool $appendSlash = false): string - { + public function getWellKnownIssuer($appendSlash = false) { + return $this->getWellKnownConfigValue('issuer') . ($appendSlash ? '/' : ''); } /** + * @return string * @throws OpenIDConnectClientException */ - public function getIssuer(): string - { + public function getIssuer() { if (!isset($this->providerConfig['issuer'])) { throw new OpenIDConnectClientException('The issuer has not been set'); @@ -1478,16 +1536,25 @@ class OpenIDConnectClient return $this->providerConfig['providerUrl']; } - public function redirect(string $url) { + /** + * @param string $url + */ + public function redirect($url) { header('Location: ' . $url); exit; } - public function setHttpProxy(string $httpProxy) { + /** + * @param string $httpProxy + */ + public function setHttpProxy($httpProxy) { $this->httpProxy = $httpProxy; } - public function setCertPath(string $certPath) { + /** + * @param string $certPath + */ + public function setCertPath($certPath) { $this->certPath = $certPath; } @@ -1498,33 +1565,48 @@ class OpenIDConnectClient return $this->certPath; } - public function setVerifyPeer(bool $verifyPeer) { + /** + * @param bool $verifyPeer + */ + public function setVerifyPeer($verifyPeer) { $this->verifyPeer = $verifyPeer; } - public function setVerifyHost(bool $verifyHost) { + /** + * @param bool $verifyHost + */ + public function setVerifyHost($verifyHost) { $this->verifyHost = $verifyHost; } + /** * Controls whether http header HTTP_UPGRADE_INSECURE_REQUESTS should be considered * defaults to true + * @param bool $httpUpgradeInsecureRequests */ - public function setHttpUpgradeInsecureRequests(bool $httpUpgradeInsecureRequests) { + public function setHttpUpgradeInsecureRequests($httpUpgradeInsecureRequests) { $this->httpUpgradeInsecureRequests = $httpUpgradeInsecureRequests; } - public function getVerifyHost(): bool - { + /** + * @return bool + */ + public function getVerifyHost() { return $this->verifyHost; } - public function getVerifyPeer(): bool - { + /** + * @return bool + */ + public function getVerifyPeer() { return $this->verifyPeer; } - public function getHttpUpgradeInsecureRequests(): bool + /** + * @return bool + */ + public function getHttpUpgradeInsecureRequests() { return $this->httpUpgradeInsecureRequests; } @@ -1533,8 +1615,10 @@ class OpenIDConnectClient * Use this for custom issuer validation * The given function should accept the issuer string from the JWT claim as the only argument * and return true if the issuer is valid, otherwise return false + * + * @param callable $issuerValidator */ - public function setIssuerValidator(callable $issuerValidator) { + public function setIssuerValidator($issuerValidator) { $this->issuerValidator = $issuerValidator; } @@ -1543,20 +1627,24 @@ class OpenIDConnectClient * The given function should accept the token_endpoint string as the only argument * and return a jwt signed with your private key according to: * https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication + * + * @param callable $privateKeyJwtGenerator */ - public function setPrivateKeyJwtGenerator(callable $privateKeyJwtGenerator) { + public function setPrivateKeyJwtGenerator($privateKeyJwtGenerator) { $this->privateKeyJwtGenerator = $privateKeyJwtGenerator; } - public function setAllowImplicitFlow(bool $allowImplicitFlow) { + /** + * @param bool $allowImplicitFlow + */ + public function setAllowImplicitFlow($allowImplicitFlow) { $this->allowImplicitFlow = $allowImplicitFlow; } /** * @return bool */ - public function getAllowImplicitFlow(): bool - { + public function getAllowImplicitFlow() { return $this->allowImplicitFlow; } @@ -1567,15 +1655,21 @@ class OpenIDConnectClient * @param array $array * simple key => value */ - public function providerConfigParam(array $array) { + public function providerConfigParam($array) { $this->providerConfig = array_merge($this->providerConfig, $array); } - public function setClientSecret(string $clientSecret) { + /** + * @param string $clientSecret + */ + public function setClientSecret($clientSecret) { $this->clientSecret = $clientSecret; } - public function setClientID(string $clientID) { + /** + * @param string $clientID + */ + public function setClientID($clientID) { $this->clientID = $clientID; } @@ -1596,7 +1690,7 @@ class OpenIDConnectClient $response = $this->fetchURL($registration_endpoint, json_encode($send_object)); - $json_response = json_decode($response, false); + $json_response = json_decode($response); // Throw some errors if we encounter them if ($json_response === false) { @@ -1614,8 +1708,10 @@ class OpenIDConnectClient if (isset($json_response->{'client_secret'})) { $this->setClientSecret($json_response->{'client_secret'}); } else { - throw new OpenIDConnectClientException('Error registering: Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them'); + throw new OpenIDConnectClientException('Error registering: + Please contact the OpenID Connect provider and obtain a Client ID and Secret directly from them'); } + } /** @@ -1628,9 +1724,8 @@ class OpenIDConnectClient * @param string|null $clientSecret * @return mixed * @throws OpenIDConnectClientException - * @throws Exception */ - public function introspectToken(string $token, string $token_type_hint = '', string $clientId = null, string $clientSecret = null) { + public function introspectToken($token, $token_type_hint = '', $clientId = null, $clientSecret = null) { $introspection_endpoint = $this->getProviderConfigValue('introspection_endpoint'); $token_endpoint_auth_methods_supported = $this->getProviderConfigValue('token_endpoint_auth_methods_supported', ['client_secret_basic']); @@ -1639,8 +1734,8 @@ class OpenIDConnectClient if ($token_type_hint) { $post_data['token_type_hint'] = $token_type_hint; } - $clientId = $clientId ?? $this->clientID; - $clientSecret = $clientSecret ?? $this->clientSecret; + $clientId = $clientId !== null ? $clientId : $this->clientID; + $clientSecret = $clientSecret !== null ? $clientSecret : $this->clientSecret; // Convert token params to string format $headers = ['Authorization: Basic ' . base64_encode(urlencode($clientId) . ':' . urlencode($clientSecret)), @@ -1649,7 +1744,7 @@ class OpenIDConnectClient if ($this->supportsAuthMethod('client_secret_jwt', $token_endpoint_auth_methods_supported)) { $client_assertion_type = $this->getProviderConfigValue('client_assertion_type'); $client_assertion = $this->getJWTClientAssertion($this->getProviderConfigValue('introspection_endpoint')); - + $post_data['client_assertion_type']=$client_assertion_type; $post_data['client_assertion'] = $client_assertion; $headers = ['Accept: application/json']; @@ -1657,7 +1752,7 @@ class OpenIDConnectClient $post_params = http_build_query($post_data, '', '&'); - return json_decode($this->fetchURL($introspection_endpoint, $post_params, $headers), false); + return json_decode($this->fetchURL($introspection_endpoint, $post_params, $headers)); } /** @@ -1671,7 +1766,7 @@ class OpenIDConnectClient * @return mixed * @throws OpenIDConnectClientException */ - public function revokeToken(string $token, string $token_type_hint = '', string $clientId = null, string $clientSecret = null) { + public function revokeToken($token, $token_type_hint = '', $clientId = null, $clientSecret = null) { $revocation_endpoint = $this->getProviderConfigValue('revocation_endpoint'); $post_data = ['token' => $token]; @@ -1679,23 +1774,28 @@ class OpenIDConnectClient if ($token_type_hint) { $post_data['token_type_hint'] = $token_type_hint; } - $clientId = $clientId ?? $this->clientID; - $clientSecret = $clientSecret ?? $this->clientSecret; + $clientId = $clientId !== null ? $clientId : $this->clientID; + $clientSecret = $clientSecret !== null ? $clientSecret : $this->clientSecret; // Convert token params to string format $post_params = http_build_query($post_data, '', '&'); $headers = ['Authorization: Basic ' . base64_encode(urlencode($clientId) . ':' . urlencode($clientSecret)), 'Accept: application/json']; - return json_decode($this->fetchURL($revocation_endpoint, $post_params, $headers), false); + return json_decode($this->fetchURL($revocation_endpoint, $post_params, $headers)); } - public function getClientName(): string - { + /** + * @return string + */ + public function getClientName() { return $this->clientName; } - public function setClientName(string $clientName) { + /** + * @param string $clientName + */ + public function setClientName($clientName) { $this->clientName = $clientName; } @@ -1714,26 +1814,42 @@ class OpenIDConnectClient } /** + * @return bool + */ + public function canVerifySignatures() { + return class_exists('\phpseclib3\Crypt\RSA') || class_exists('\phpseclib\Crypt\RSA') || class_exists('Crypt_RSA'); + } + + /** * Set the access token. * * May be required for subclasses of this Client. + * + * @param string $accessToken + * @return void */ - public function setAccessToken(string $accessToken) { + public function setAccessToken($accessToken) { $this->accessToken = $accessToken; } - public function getAccessToken(): string - { + /** + * @return string + */ + public function getAccessToken() { return $this->accessToken; } - public function getRefreshToken(): string - { + /** + * @return string + */ + public function getRefreshToken() { return $this->refreshToken; } - public function getIdToken(): string - { + /** + * @return string + */ + public function getIdToken() { return $this->idToken; } @@ -1766,7 +1882,7 @@ class OpenIDConnectClient } /** - * @return object + * @return string */ public function getTokenResponse() { return $this->tokenResponse; @@ -1774,9 +1890,11 @@ class OpenIDConnectClient /** * Stores nonce + * + * @param string $nonce + * @return string */ - protected function setNonce(string $nonce): string - { + protected function setNonce($nonce) { $this->setSessionKey('openid_connect_nonce', $nonce); return $nonce; } @@ -1801,9 +1919,11 @@ class OpenIDConnectClient /** * Stores $state + * + * @param string $state + * @return string */ - protected function setState(string $state): string - { + protected function setState($state) { $this->setSessionKey('openid_connect_state', $state); return $state; } @@ -1828,9 +1948,11 @@ class OpenIDConnectClient /** * Stores $codeVerifier + * + * @param string $codeVerifier + * @return string */ - protected function setCodeVerifier(string $codeVerifier): string - { + protected function setCodeVerifier($codeVerifier) { $this->setSessionKey('openid_connect_code_verifier', $codeVerifier); return $codeVerifier; } @@ -1858,36 +1980,60 @@ class OpenIDConnectClient * * @return int */ - public function getResponseCode(): int - { + public function getResponseCode() { return $this->responseCode; } /** - * Get the content type from last action/curl request. - * - * @return string|null - */ - public function getResponseContentType() - { - return $this->responseContentType; - } - - /** * Set timeout (seconds) * * @param int $timeout */ - public function setTimeout(int $timeout) { + public function setTimeout($timeout) { $this->timeOut = $timeout; } - public function getTimeout(): int - { + /** + * @return int + */ + public function getTimeout() { return $this->timeOut; } /** + * Safely calculate length of binary string + * @param string $str + * @return int + */ + private static function safeLength($str) { + if (function_exists('mb_strlen')) { + return mb_strlen($str, '8bit'); + } + return strlen($str); + } + + /** + * Where hash_equals is not available, this provides a timing-attack safe string comparison + * @param string $str1 + * @param string $str2 + * @return bool + */ + private static function hashEquals($str1, $str2) { + $len1=static::safeLength($str1); + $len2=static::safeLength($str2); + + //compare strings without any early abort... + $len = min($len1, $len2); + $status = 0; + for ($i = 0; $i < $len; $i++) { + $status |= (ord($str1[$i]) ^ ord($str2[$i])); + } + //if strings were different lengths, we fail + $status |= ($len1 ^ $len2); + return ($status === 0); + } + + /** * Use session to manage a nonce */ protected function startSession() { @@ -1902,7 +2048,7 @@ class OpenIDConnectClient session_write_close(); } - protected function getSessionKey(string $key) { + protected function getSessionKey($key) { $this->startSession(); if (array_key_exists($key, $_SESSION)) { @@ -1911,23 +2057,19 @@ class OpenIDConnectClient return false; } - protected function setSessionKey(string $key, $value) { + protected function setSessionKey($key, $value) { $this->startSession(); $_SESSION[$key] = $value; } - protected function unsetSessionKey(string $key) { + protected function unsetSessionKey($key) { $this->startSession(); unset($_SESSION[$key]); } - /** - * @throws Exception - */ - protected function getJWTClientAssertion($aud): string - { + protected function getJWTClientAssertion($aud) { $jti = hash('sha256',bin2hex(random_bytes(64))); $now = time(); @@ -1943,7 +2085,7 @@ class OpenIDConnectClient ]); // Encode Header to Base64Url String $base64UrlHeader = $this->urlEncode($header); - + // Encode Payload to Base64Url String $base64UrlPayload = $this->urlEncode($payload); @@ -1958,10 +2100,12 @@ class OpenIDConnectClient // Encode Signature to Base64Url String $base64UrlSignature = $this->urlEncode($signature); + + $jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; - return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; + return $jwt; } - + public function setUrlEncoding($curEncoding) { switch ($curEncoding) { @@ -1976,20 +2120,27 @@ class OpenIDConnectClient default: break; } + } - public function getScopes(): array - { + /** + * @return array + */ + public function getScopes() { return $this->scopes; } - public function getResponseTypes(): array - { + /** + * @return array + */ + public function getResponseTypes() { return $this->responseTypes; } - public function getAuthParams(): array - { + /** + * @return array + */ + public function getAuthParams() { return $this->authParams; } @@ -2008,8 +2159,10 @@ class OpenIDConnectClient return $this->privateKeyJwtGenerator; } - public function getLeeway(): int - { + /** + * @return int + */ + public function getLeeway() { return $this->leeway; } @@ -2020,7 +2173,10 @@ class OpenIDConnectClient return $this->codeChallengeMethod; } - public function setCodeChallengeMethod(string $codeChallengeMethod) { + /** + * @param string $codeChallengeMethod + */ + public function setCodeChallengeMethod($codeChallengeMethod) { $this->codeChallengeMethod = $codeChallengeMethod; } @@ -2032,27 +2188,26 @@ class OpenIDConnectClient throw new OpenIDConnectClientException('Self signed JWK header is not valid'); } - /** - * @param string $jwe The JWE to decrypt - * @return string the JWT payload - * @throws OpenIDConnectClientException + /* + * @return string */ - protected function handleJweResponse(string $jwe): string - { - throw new OpenIDConnectClientException('JWE response is not supported, please extend the class and implement this method'); - } - - public function getSidFromBackChannel(): string - { + public function getSidFromBackChannel() { return $this->backChannelSid; } - public function getSubjectFromBackChannel(): string - { + /** + * @return string + */ + public function getSubjectFromBackChannel() { return $this->backChannelSubject; } - public function supportsAuthMethod(string $auth_method, array $token_endpoint_auth_methods_supported): bool + /** + * @param string $auth_method + * @param array $token_endpoint_auth_methods_supported + * @return bool + */ + public function supportsAuthMethod($auth_method, $token_endpoint_auth_methods_supported) { # client_secret_jwt has to explicitly be enabled if (!in_array($auth_method, $this->token_endpoint_auth_methods_supported, true)) { @@ -2061,9 +2216,4 @@ class OpenIDConnectClient return in_array($auth_method, $token_endpoint_auth_methods_supported, true); } - - protected function getUserAgent(): string - { - return "jumbojett/OpenID-Connect-PHP"; - } } diff --git a/vendor/jumbojett/openid-connect-php/tests/OpenIDConnectClientTest.php b/vendor/jumbojett/openid-connect-php/tests/OpenIDConnectClientTest.php index a16be71..dd3321b 100644 --- a/vendor/jumbojett/openid-connect-php/tests/OpenIDConnectClientTest.php +++ b/vendor/jumbojett/openid-connect-php/tests/OpenIDConnectClientTest.php @@ -23,7 +23,7 @@ class OpenIDConnectClientTest extends TestCase public function testAuthenticateDoesNotThrowExceptionIfClaimsIsMissingNonce() { - $fakeClaims = new StdClass(); + $fakeClaims = new \StdClass(); $fakeClaims->iss = 'fake-issuer'; $fakeClaims->aud = 'fake-client-id'; $fakeClaims->nonce = null; @@ -33,10 +33,10 @@ class OpenIDConnectClientTest extends TestCase $_SESSION['openid_connect_state'] = false; /** @var OpenIDConnectClient | MockObject $client */ - $client = $this->getMockBuilder(OpenIDConnectClient::class)->setMethods(['decodeJWT', 'getProviderConfigValue', 'verifyJWTSignature'])->getMock(); + $client = $this->getMockBuilder(OpenIDConnectClient::class)->setMethods(['decodeJWT', 'getProviderConfigValue', 'verifyJWTsignature'])->getMock(); $client->method('decodeJWT')->willReturn($fakeClaims); $client->method('getProviderConfigValue')->with('jwks_uri')->willReturn(true); - $client->method('verifyJWTSignature')->willReturn(true); + $client->method('verifyJWTsignature')->willReturn(true); $client->setClientID('fake-client-id'); $client->setIssuer('fake-issuer'); @@ -60,7 +60,7 @@ class OpenIDConnectClientTest extends TestCase { $client = new OpenIDConnectClient('https://example.com', 'foo', 'bar', 'baz'); $serialized = serialize($client); - $this->assertInstanceOf(OpenIDConnectClient::class, unserialize($serialized)); + $this->assertInstanceOf('Jumbojett\OpenIDConnectClient', unserialize($serialized)); } /** @@ -75,7 +75,7 @@ class OpenIDConnectClientTest extends TestCase $this->assertEquals($expected, $client->supportsAuthMethod($authMethod, $idpAuthMethods)); } - public function provider(): array + public function provider() { return [ 'client_secret_basic - default config' => [true, 'client_secret_basic', null, ['client_secret_basic']], @@ -88,153 +88,4 @@ class OpenIDConnectClientTest extends TestCase ]; } - - /** - * @covers Jumbojett\\OpenIDConnectClient::verifyLogoutTokenClaims - * @dataProvider provideTestVerifyLogoutTokenClaimsData - * @throws OpenIDConnectClientException - */ - public function testVerifyLogoutTokenClaims( $claims, $expectedResult ) - { - /** @var OpenIDConnectClient | MockObject $client */ - $client = $this->getMockBuilder(OpenIDConnectClient::class)->setMethods(['decodeJWT'])->getMock(); - - $client->setClientID('fake-client-id'); - $client->setIssuer('fake-issuer'); - $client->setIssuerValidator(function() { - return true; - }); - $client->setProviderURL('https://jwt.io/'); - - $actualResult = $client->verifyLogoutTokenClaims( $claims ); - - $this->assertEquals( $expectedResult, $actualResult ); - } - - /** - * @return array - */ - public function provideTestVerifyLogoutTokenClaimsData(): array - { - return [ - 'valid-single-aud' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => 'fake-client-id', - 'sid' => 'fake-client-sid', - 'sub' => 'fake-client-sub', - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - ], - true - ], - 'valid-multiple-auds' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'sub' => 'fake-client-sub', - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - ], - true - ], - 'invalid-no-sid-and-no-sub' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - ], - false - ], - 'valid-no-sid' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sub' => 'fake-client-sub', - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - ], - true - ], - 'valid-no-sub' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - ], - true - ], - 'invalid-with-nonce' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'iat' => time(), - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ], - 'nonce' => 'must-not-be-set' - ], - false - ], - 'invalid-no-events' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'iat' => time(), - 'nonce' => 'must-not-be-set' - ], - false - ], - 'invalid-no-backchannel-event' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'iat' => time(), - 'events' => (object) [], - 'nonce' => 'must-not-be-set' - ], - false - ], - 'invalid-no-iat' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ] - ], - false - ], - 'invalid-bad-iat' => [ - (object)[ - 'iss' => 'fake-issuer', - 'aud' => [ 'fake-client-id', 'some-other-aud' ], - 'sid' => 'fake-client-sid', - 'iat' => time() + 301, - 'events' => (object) [ - 'http://schemas.openid.net/event/backchannel-logout' => (object)[] - ] - ], - false - ], - ]; - } } diff --git a/vendor/jumbojett/openid-connect-php/tests/TokenVerificationTest.php b/vendor/jumbojett/openid-connect-php/tests/TokenVerificationTest.php index 0715911..5844992 100644 --- a/vendor/jumbojett/openid-connect-php/tests/TokenVerificationTest.php +++ b/vendor/jumbojett/openid-connect-php/tests/TokenVerificationTest.php @@ -2,7 +2,6 @@ use Jumbojett\OpenIDConnectClient; -use Jumbojett\OpenIDConnectClientException; use PHPUnit\Framework\MockObject\MockObject; use Yoast\PHPUnitPolyfills\TestCases\TestCase; @@ -11,7 +10,7 @@ class TokenVerificationTest extends TestCase /** * @param $alg * @param $jwt - * @throws OpenIDConnectClientException + * @throws \Jumbojett\OpenIDConnectClientException * @dataProvider providesTokens */ public function testTokenVerification($alg, $jwt) @@ -21,12 +20,12 @@ class TokenVerificationTest extends TestCase $client->method('fetchUrl')->willReturn(file_get_contents(__DIR__ . "/data/jwks-$alg.json")); $client->setProviderURL('https://jwt.io/'); $client->providerConfigParam(['jwks_uri' => 'https://jwt.io/.well-known/jwks.json']); - $verified = $client->verifyJWTSignature($jwt); + $verified = $client->verifyJWTsignature($jwt); self::assertTrue($verified); $client->setAccessToken($jwt); } - public function providesTokens(): array + public function providesTokens() { return [ 'PS256' => ['ps256', 'eyJhbGciOiJQUzI1NiIsImtpZCI6Imtvbm5lY3RkLXRva2Vucy1zaWduaW5nLWtleSIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJrcG9wLWh0dHBzOi8va29wYW5vLmRlbW8vbWVldC8iLCJleHAiOjE1NjgzNzE0NjEsImp0aSI6IkpkR0tDbEdOTXl2VXJpcmlRRUlWUXZCVmttT2FfQkRjIiwiaWF0IjoxNTY4MzcxMjIxLCJpc3MiOiJodHRwczovL2tvcGFuby5kZW1vIiwic3ViIjoiUHpUVWp3NHBlXzctWE5rWlBILXJxVHE0MTQ1Z3lDdlRvQmk4V1E5bFBrcW5rbEc1aktvRU5LM21Qb0I1WGY1ZTM5dFRMR2RKWXBMNEJubXFnelpaX0FAa29ubmVjdCIsImtjLmlzQWNjZXNzVG9rZW4iOnRydWUsImtjLmF1dGhvcml6ZWRTY29wZXMiOlsicHJvZmlsZSIsImVtYWlsIiwia29wYW5vL2t3bSIsImtvcGFuby9nYyIsImtvcGFuby9rdnMiLCJvcGVuaWQiXSwia2MuYXV0aG9yaXplZENsYWltcyI6eyJpZF90b2tlbiI6eyJuYW1lIjpudWxsfX0sImtjLmlkZW50aXR5Ijp7ImtjLmkuZG4iOiJKb25hcyBCcmVra2UiLCJrYy5pLmlkIjoiQUFBQUFLd2hxVkJBMCs1SXN4bjdwMU13UkNVQkFBQUFCZ0FBQUJzQUFBQk5VVDA5QUFBQUFBPT0iLCJrYy5pLnVuIjoidXNlcjEiLCJrYy5pLnVzIjoiTVEifSwia2MucHJvdmlkZXIiOiJpZGVudGlmaWVyLWtjIn0.hGRuXvul2kOiALHexwYp5MBEJVwz1YV3ehyM3AOuwCoK2w5sJxdciqqY_TfXCKyO6nAEbYLK3J0CBOjfup_IG0aCZcwzjto8khYlc4ezXkGnFsbJBNQdDGkpHtWnioWx-OJ3cXvY9F8aOvjaq0gw11ZDAcqQl0g7LTbJ9-J_yx0pmy3NGai2JB30Fh1OgSDzYfxWnE0RRgZG-x68e65RXfSBaEGW85OUh4wihxO2zdTGAHJ3Iq_-QAG4yRbXZtLx3ZspG7LNmqG-YE3huy3Rd8u3xrJNhmUOfEnz3x07q7VW0cj9NedX98BAbj3iNvksQsE0oG0J_f_Tu8Ai8VbWB72sJuXZWxANDKdz0BBYLzXhsjXkNByRq9x3zqDVsX-cVHei_XudxEOVRBjhkvW2MmIjcAHNKCKsdar865-gFG9McP4PCcBlY28tC0Cvnzyi83LBfpGRXdl6MJunnUsKQ1C79iCoVI1doK1erFN959Q-TGJfJA3Tr5LNpuGawB5rpe1nDGWvmYhg3uYfNl8uTTyvNgvvejcflEb2DURuXdqABuSiP7RkDWYtzx6mq49G0tRxelBbvyjQ2id2QjmRRdQ6dHEZ2NCJ51b8OFoDJBtxN1CD62TTxa3FUqCdZAPAUR3hHn_69vYq82MR514s-Gb67A6j2PbMPFATQP2UdK8'] |