diff --git a/CHANGELOG.md b/CHANGELOG.md index 30804ab09d760d981d1bc360e935dfeb0290a424..bae57dd3e57be1d28b30d152f39f8f1629c85ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ _Release: 2023-03-01 * Move `lib` to `src` * Move `www` to `public` * Use ssp2 final release +* firebase/php-jwt 6 support ## v4.0.0-alpha.1 diff --git a/composer.json b/composer.json index 5b4287a0a7f2b7bad9d202fda29c7065b4ad8dc6..11b069f89c2888d60e546e62bf1799a7770bbe19 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "simplesamlphp/composer-module-installer": "^1.1", "league/oauth2-client": "^2.6", "simplesamlphp/simplesamlphp": "^v2.0.0", - "firebase/php-jwt": "^5.0", + "firebase/php-jwt": "^5.5|^6", "kevinrob/guzzle-cache-middleware": "^3.2", "psr/cache": "^1.0", "symfony/cache": "^5.0|^4.3|^3.4", @@ -24,6 +24,11 @@ "phpunit/phpunit": "^9.5", "psalm/plugin-phpunit": "^0.18.3" }, + "autoload": { + "psr-4": { + "SimpleSAML\\Module\\authoauth2\\": "src/" + } + }, "autoload-dev": { "psr-4": { "Test\\SimpleSAML\\": "tests/lib/" diff --git a/phpcs.xml b/phpcs.xml index c1f3c3718ee450b0bea243f4507987c07d61e2f5..a5d992867bc7f5d8966b927751c120e60418b4df 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -6,9 +6,9 @@ By default it is less stringent about long lines than other coding standards </description> - <file>lib</file> + <file>src</file> <file>tests</file> - <file>www</file> + <file>public</file> <!-- Use this to exclude paths. You can have multiple patterns --> <exclude-pattern>tests/config/*</exclude-pattern> diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 6226327d2bc20993e0706a9669e6a0e91afe318b..43f6a6b45ed2f21d6ea2fdb8fe3793e838abb380 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,59 +1,62 @@ <?xml version="1.0" encoding="UTF-8"?> -<files psalm-version="4.30.0@d0bc6e25d89f649e4f36a534f330f8bb4643dd69"> - <file src="lib/AttributeManipulator.php"> - <MixedArgument occurrences="1"> +<files psalm-version="5.7.7@e028ba46ba0d7f9a78bc3201c251e137383e145f"> + <file src="src/AttributeManipulator.php"> + <MixedArgument> <code>$input</code> </MixedArgument> - <MixedAssignment occurrences="3"> + <MixedAssignment> <code>$value</code> <code>$value</code> <code>$value</code> </MixedAssignment> </file> - <file src="lib/Auth/Source/BitbucketAuth.php"> - <MixedArrayAccess occurrences="3"> - <code>$response["values"][$i]</code> - <code>$response["values"][$i]</code> - <code>$response["values"][$i]</code> + <file src="src/Auth/Source/BitbucketAuth.php"> + <MixedArrayAccess> + <code><![CDATA[$response["values"][$i]]]></code> + <code><![CDATA[$response["values"][$i]]]></code> + <code><![CDATA[$response["values"][$i]]]></code> + <code><![CDATA[$response["values"][$i]["email"]]]></code> + <code><![CDATA[$response["values"][$i]["is_primary"]]]></code> + <code><![CDATA[$response["values"][$i]["type"]]]></code> </MixedArrayAccess> - <MixedArrayAssignment occurrences="1"> + <MixedArrayAssignment> <code>$state['Attributes'][$prefix . 'email']</code> </MixedArrayAssignment> - <MixedAssignment occurrences="1"> + <MixedAssignment> <code>$response</code> </MixedAssignment> </file> - <file src="lib/Auth/Source/LinkedInV2Auth.php"> - <MixedArgument occurrences="1"> + <file src="src/Auth/Source/LinkedInV2Auth.php"> + <MixedArgument> <code>$attributes[$attributeName]['localized']</code> </MixedArgument> - <MixedArrayAccess occurrences="1"> - <code>$response["elements"][0]["handle~"]["emailAddress"]</code> + <MixedArrayAccess> + <code><![CDATA[$response["elements"][0]["handle~"]["emailAddress"]]]></code> </MixedArrayAccess> - <MixedArrayAssignment occurrences="1"> + <MixedArrayAssignment> <code>$state['Attributes'][$prefix . 'emailAddress']</code> </MixedArrayAssignment> - <MixedAssignment occurrences="1"> + <MixedAssignment> <code>$response</code> </MixedAssignment> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>string|false|null</code> </MixedInferredReturnType> - <MixedReturnStatement occurrences="1"> + <MixedReturnStatement> <code>reset($attributes[$attributeName]['localized'])</code> </MixedReturnStatement> </file> - <file src="lib/Auth/Source/MicrosoftHybridAuth.php"> - <MixedArgument occurrences="1"> - <code>$accessToken->getValues()['id_token']</code> + <file src="src/Auth/Source/MicrosoftHybridAuth.php"> + <MixedArgument> + <code><![CDATA[$accessToken->getValues()['id_token']]]></code> </MixedArgument> - <MixedArrayAssignment occurrences="2"> + <MixedArrayAssignment> <code>$state['Attributes'][$prefix . 'mail']</code> <code>$state['Attributes'][$prefix . 'name']</code> </MixedArrayAssignment> </file> - <file src="lib/Auth/Source/OAuth2.php"> - <MixedArgument occurrences="7"> + <file src="src/Auth/Source/OAuth2.php"> + <MixedArgument> <code>$apiAttributes</code> <code>$apiUrl</code> <code>$config['urlResourceOwnerDetails']</code> @@ -62,11 +65,16 @@ <code>$state['Attributes']</code> <code>$templateArray</code> </MixedArgument> - <MixedArgumentTypeCoercion occurrences="1"/> - <MixedArrayAccess occurrences="1"> + <MixedArgumentTypeCoercion> + <code><![CDATA[Middleware::log( + new \SAML2\Compat\Ssp\Logger(), + new MessageFormatter("authoauth2: $providerLabel $format") + )]]></code> + </MixedArgumentTypeCoercion> + <MixedArrayAccess> <code>$templateArray[0]</code> </MixedArrayAccess> - <MixedAssignment occurrences="6"> + <MixedAssignment> <code>$apiAttributes</code> <code>$apiUrl</code> <code>$data</code> @@ -74,30 +82,33 @@ <code>$template</code> <code>$templateArray</code> </MixedAssignment> - <MixedInferredReturnType occurrences="2"> + <MixedInferredReturnType> <code>array</code> <code>string[]</code> </MixedInferredReturnType> - <MixedReturnStatement occurrences="2"> + <MixedReturnStatement> <code>$data</code> - <code>$provider->getParsedResponse($apiRequest)</code> + <code><![CDATA[$provider->getParsedResponse($apiRequest)]]></code> </MixedReturnStatement> + <UnnecessaryVarAnnotation> + <code>0|positive-int</code> + </UnnecessaryVarAnnotation> </file> - <file src="lib/Auth/Source/OpenIDConnect.php"> - <MixedArgument occurrences="3"> + <file src="src/Auth/Source/OpenIDConnect.php"> + <MixedArgument> <code>$handler</code> <code>$id_token</code> <code>$state['Attributes']</code> </MixedArgument> - <MixedArgumentTypeCoercion occurrences="2"> + <MixedArgumentTypeCoercion> <code>$key</code> <code>$key</code> </MixedArgumentTypeCoercion> - <MixedArrayAssignment occurrences="2"> - <code>$httpClient->getConfig()['handler']</code> + <MixedArrayAssignment> + <code><![CDATA[$httpClient->getConfig()['handler']]]></code> <code>$state['PersistentAuthData'][]</code> </MixedArrayAssignment> - <MixedAssignment occurrences="5"> + <MixedAssignment> <code>$handler</code> <code>$id_token</code> <code>$id_token</code> @@ -105,139 +116,146 @@ <code>$value</code> </MixedAssignment> </file> - <file src="lib/Auth/Source/OrcidOIDCAuth.php"> - <MixedArrayAccess occurrences="4"> - <code>$e["email"]</code> - <code>$e["primary"]</code> - <code>$e["primary"]</code> + <file src="src/Auth/Source/OrcidOIDCAuth.php"> + <MixedArrayAccess> + <code><![CDATA[$e["email"]]]></code> + <code><![CDATA[$e["primary"]]]></code> + <code><![CDATA[$e["primary"]]]></code> <code>$state['Attributes'][$prefix . 'sub']</code> + <code>$state['Attributes'][$prefix . 'sub'][0]</code> </MixedArrayAccess> - <MixedArrayAssignment occurrences="1"> + <MixedArrayAssignment> <code>$state['Attributes'][$prefix . 'email']</code> </MixedArrayAssignment> - <MixedAssignment occurrences="3"> + <MixedAssignment> <code>$e</code> <code>$email</code> <code>$response</code> </MixedAssignment> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>string</code> </MixedInferredReturnType> - <MixedReturnStatement occurrences="1"> + <MixedReturnStatement> + <code>$email</code> <code>$email</code> </MixedReturnStatement> </file> - <file src="lib/OAuth2ResponseHandler.php"> - <MixedArgument occurrences="3"> + <file src="src/OAuth2ResponseHandler.php"> + <MixedArgument> <code>$request['code']</code> <code>$sourceId</code> <code>$stateIdWithPrefix</code> </MixedArgument> - <MixedAssignment occurrences="3"> + <MixedAssignment> <code>$error</code> <code>$sourceId</code> <code>$stateIdWithPrefix</code> </MixedAssignment> - <MixedOperand occurrences="3"> + <MixedOperand> <code>$error</code> <code>@$request['error_description']</code> <code>@$request['error_description']</code> </MixedOperand> </file> - <file src="lib/OIDCLogoutHandler.php"> - <MixedArgument occurrences="3"> + <file src="src/OIDCLogoutHandler.php"> + <MixedArgument> <code>$sourceId</code> <code>$sourceId</code> <code>$stateIdWithPrefix</code> </MixedArgument> - <MixedAssignment occurrences="3"> + <MixedAssignment> <code>$sourceId</code> <code>$sourceId</code> <code>$stateIdWithPrefix</code> </MixedAssignment> </file> - <file src="lib/Providers/AdjustableGenericProvider.php"> - <MixedAssignment occurrences="1"> + <file src="src/Providers/AdjustableGenericProvider.php"> + <MixedAssignment> <code>$toAdd[$param]</code> </MixedAssignment> </file> - <file src="lib/Providers/OpenIDConnectProvider.php"> - <MixedArgument occurrences="6"> - <code>$claims->aud</code> - <code>$claims->iss</code> + <file src="src/Providers/OpenIDConnectProvider.php"> + <MixedArgument> + <code><![CDATA[$claims->aud]]></code> + <code><![CDATA[$claims->iss]]></code> + <code>$key</code> <code>$key</code> <code>$key['e']</code> <code>$key['n']</code> <code>$result['id_token']</code> </MixedArgument> - <MixedArrayAccess occurrences="5"> + <MixedArgumentTypeCoercion> + <code>$keys</code> + </MixedArgumentTypeCoercion> + <MixedArrayAccess> <code>$key['e']</code> <code>$key['kid']</code> <code>$key['kty']</code> <code>$key['n']</code> <code>$key['x5c']</code> </MixedArrayAccess> - <MixedAssignment occurrences="2"> + <MixedAssignment> <code>$error</code> <code>$key</code> + <code>$key</code> </MixedAssignment> - <MixedOperand occurrences="2"> + <MixedOperand> <code>$config['issuer']</code> <code>$x5c[0]</code> </MixedOperand> </file> <file src="tests/config/authsources.php"> - <UnusedVariable occurrences="1"> + <UnusedVariable> <code>$config</code> </UnusedVariable> </file> <file src="tests/config/config.php"> - <UnusedVariable occurrences="1"> + <UnusedVariable> <code>$config</code> </UnusedVariable> </file> <file src="tests/config/ssp2_0-config.php"> - <UnusedVariable occurrences="1"> + <UnusedVariable> <code>$config</code> </UnusedVariable> </file> <file src="tests/lib/AttributeManipulatorTest.php"> - <MissingReturnType occurrences="1"> + <MissingReturnType> <code>testPrefixAndFlatten</code> </MissingReturnType> </file> <file src="tests/lib/Auth/Source/LinkedInV2AuthTest.php"> - <MissingReturnType occurrences="3"> + <MissingReturnType> <code>getEmailProvider</code> <code>testAttributeConversion</code> <code>testGettingEmail</code> </MissingReturnType> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>array</code> </MixedInferredReturnType> - <MixedMethodCall occurrences="5"> + <MixedMethodCall> <code>method</code> <code>willReturn</code> <code>willReturn</code> <code>with</code> <code>with</code> </MixedMethodCall> - <PossiblyInvalidArgument occurrences="2"> + <PossiblyInvalidArgument> <code>$mock</code> <code>$mock</code> </PossiblyInvalidArgument> - <PossiblyUndefinedMethod occurrences="3"> + <PossiblyUndefinedMethod> <code>expects</code> <code>method</code> <code>method</code> </PossiblyUndefinedMethod> </file> <file src="tests/lib/Auth/Source/MicrosoftHybridAuthTest.php"> - <MissingReturnType occurrences="2"> + <MissingReturnType> <code>combineOidcAndGraphProfileProvider</code> <code>testCombineOidcAndGraphProfile</code> </MissingReturnType> - <MixedMethodCall occurrences="8"> + <MixedMethodCall> <code>willReturn</code> <code>willReturn</code> <code>willReturn</code> @@ -247,10 +265,10 @@ <code>with</code> <code>with</code> </MixedMethodCall> - <PossiblyInvalidArgument occurrences="1"> + <PossiblyInvalidArgument> <code>$mock</code> </PossiblyInvalidArgument> - <PossiblyUndefinedMethod occurrences="4"> + <PossiblyUndefinedMethod> <code>method</code> <code>method</code> <code>method</code> @@ -258,10 +276,10 @@ </PossiblyUndefinedMethod> </file> <file src="tests/lib/Auth/Source/OAuth2Test.php"> - <DeprecatedMethod occurrences="1"> + <DeprecatedMethod> <code>getConfig</code> </DeprecatedMethod> - <MissingParamType occurrences="15"> + <MissingParamType> <code>$accessToken</code> <code>$accessToken</code> <code>$accessToken</code> @@ -278,10 +296,10 @@ <code>$expectedUrl</code> <code>$state</code> </MissingParamType> - <MissingPropertyType occurrences="1"> + <MissingPropertyType> <code>$module_config</code> </MissingPropertyType> - <MissingReturnType occurrences="12"> + <MissingReturnType> <code>finalStepsDataProvider</code> <code>finalStepsDataProviderWithAuthenticatedApiRequest</code> <code>testAuthenticatePerformsRedirect</code> @@ -295,7 +313,7 @@ <code>testResourceOwnerQueryParamOption</code> <code>testTooManyErrorsForRetry</code> </MissingReturnType> - <MixedArgument occurrences="7"> + <MixedArgument> <code>$config</code> <code>$config</code> <code>$config</code> @@ -304,17 +322,17 @@ <code>$expectedUrl</code> <code>$state</code> </MixedArgument> - <MixedArrayAccess occurrences="2"> + <MixedArrayAccess> <code>$clientConfig['handler']</code> <code>$state[OAuth2::AUTHID]</code> </MixedArrayAccess> - <MixedAssignment occurrences="1"> + <MixedAssignment> <code>$clientConfig</code> </MixedAssignment> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>array</code> </MixedInferredReturnType> - <MixedMethodCall occurrences="6"> + <MixedMethodCall> <code>will</code> <code>will</code> <code>will</code> @@ -322,7 +340,7 @@ <code>with</code> <code>with</code> </MixedMethodCall> - <PossiblyInvalidArgument occurrences="7"> + <PossiblyInvalidArgument> <code>$mock</code> <code>$mock</code> <code>$mockRequest</code> @@ -331,45 +349,48 @@ <code>$mockRequest</code> <code>$mockRequest</code> </PossiblyInvalidArgument> - <PossiblyUndefinedMethod occurrences="3"> + <PossiblyUndefinedMethod> <code>method</code> <code>method</code> <code>method</code> </PossiblyUndefinedMethod> </file> <file src="tests/lib/Auth/Source/OpenIDConnectTest.php"> - <MissingReturnType occurrences="3"> + <InvalidClassConstantType> + <code>AUTH_ID</code> + </InvalidClassConstantType> + <MissingReturnType> <code>testLogoutNoEndpointConfigured</code> <code>testLogoutNoIDTokenInState</code> <code>testLogoutRedirects</code> </MissingReturnType> </file> <file src="tests/lib/Auth/Source/OrcidOIDCAuthTest.php"> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>array</code> </MixedInferredReturnType> </file> <file src="tests/lib/MockOAuth2Provider.php"> - <MissingReturnType occurrences="1"> + <MissingReturnType> <code>setDelegate</code> </MissingReturnType> </file> <file src="tests/lib/MockOpenIDConnectProvider.php"> - <MissingReturnType occurrences="2"> + <MissingReturnType> <code>setConfig</code> <code>setSigningKeys</code> </MissingReturnType> </file> <file src="tests/lib/OAuth2ResponseHandlerTest.php"> - <MissingParamType occurrences="3"> + <MissingParamType> <code>$expectedException</code> <code>$expectedMessage</code> <code>$queryParams</code> </MissingParamType> - <MissingPropertyType occurrences="1"> + <MissingPropertyType> <code>$validStateValue</code> </MissingPropertyType> - <MissingReturnType occurrences="7"> + <MissingReturnType> <code>noCodeDataProvider</code> <code>testNoCodeInResponse</code> <code>testNoStateFoundInSession</code> @@ -378,12 +399,12 @@ <code>testUserCancelledErrorPage</code> <code>testValidResponse</code> </MissingReturnType> - <MixedArgument occurrences="3"> + <MixedArgument> <code>$expectedException</code> <code>$expectedMessage</code> <code>$queryParams</code> </MixedArgument> - <MixedMethodCall occurrences="8"> + <MixedMethodCall> <code>method</code> <code>method</code> <code>method</code> @@ -393,7 +414,7 @@ <code>with</code> <code>with</code> </MixedMethodCall> - <PossiblyUndefinedMethod occurrences="6"> + <PossiblyUndefinedMethod> <code>expects</code> <code>expects</code> <code>expects</code> @@ -403,44 +424,44 @@ </PossiblyUndefinedMethod> </file> <file src="tests/lib/OIDCLogoutHandlerTest.php"> - <MissingReturnType occurrences="4"> + <MissingReturnType> <code>testCanHandle</code> <code>testNoStateFoundInSession</code> <code>testUnhandleableResponse</code> <code>testValidResponse</code> </MissingReturnType> - <MixedMethodCall occurrences="1"> + <MixedMethodCall> <code>method</code> </MixedMethodCall> - <PossiblyUndefinedMethod occurrences="1"> + <PossiblyUndefinedMethod> <code>expects</code> </PossiblyUndefinedMethod> </file> <file src="tests/lib/Providers/AdjustableGenericProviderTest.php"> - <MissingParamType occurrences="1"> + <MissingParamType> <code>$expectedQueryString</code> </MissingParamType> - <MissingReturnType occurrences="2"> + <MissingReturnType> <code>testNoAdjustmentsToUrl</code> <code>testSetScopes</code> </MissingReturnType> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>array</code> </MixedInferredReturnType> </file> <file src="tests/lib/Providers/OpenIDConnectProviderTest.php"> - <MissingParamType occurrences="2"> + <MissingParamType> <code>$expectedMessage</code> <code>$idToken</code> </MissingParamType> - <MixedArgument occurrences="2"> + <MixedArgument> <code>$expectedMessage</code> <code>$idToken</code> </MixedArgument> - <MixedInferredReturnType occurrences="1"> + <MixedInferredReturnType> <code>array</code> </MixedInferredReturnType> - <PossiblyFalseOperand occurrences="1"> + <PossiblyFalseOperand> <code>getenv('SIMPLESAMLPHP_CONFIG_DIR')</code> </PossiblyFalseOperand> </file> diff --git a/psalm.xml b/psalm.xml index fe54d757d8fc8b955f4d142417641ddaf6b8e55f..aede9b0f3865814dac4f6bff288dc0bac870b1a4 100644 --- a/psalm.xml +++ b/psalm.xml @@ -10,7 +10,7 @@ errorBaseline="psalm-baseline.xml" > <projectFiles> - <directory name="lib"/> + <directory name="src"/> <!-- Too many errors in test folder at the moment --> <directory name="tests"/> <!-- <directory name="templates" /> --> diff --git a/src/Providers/OpenIDConnectProvider.php b/src/Providers/OpenIDConnectProvider.php index 149c3c9281832a07037efcb26a93cd1ac9afa159..23d4d01565d9475395b3a0e3f43d8b5cc3740bc2 100644 --- a/src/Providers/OpenIDConnectProvider.php +++ b/src/Providers/OpenIDConnectProvider.php @@ -97,8 +97,15 @@ class OpenIDConnectProvider extends AbstractProvider public function verifyIdToken(string $id_token): void { try { - $keys = $this->getSigningKeys(); - $claims = JWT\JWT::decode($id_token, $keys, ['RS256']); + $keysRaw = $this->getSigningKeys(); + $keys = []; + // Be explicit about key algorithms to avoid bug reports of key confusion. + foreach ($keysRaw as $kid => $key) { + $keys[$kid] = new JWT\Key($key, 'RS256'); + } + // Once firebase/php-jwt 5.5 support is dropped we can move to firebase's parsing + //JWT\JWK::parseKeySet($keys, 'RS256'); + $claims = JWT\JWT::decode($id_token, $keys); $aud = is_array($claims->aud) ? $claims->aud : [$claims->aud]; if (!in_array($this->clientId, $aud)) {