Skip to content
Snippets Groups Projects
Commit 6c1b7f02 authored by Patrick Radtke's avatar Patrick Radtke
Browse files

More psalm fixes; better config typing in OIDC

parent a3bbb5cf
No related branches found
No related tags found
No related merge requests found
......@@ -37,7 +37,7 @@
"validate": [
"vendor/bin/phpunit --no-coverage",
"vendor/bin/phpcs -p",
"vendor/bin/psalm"
"vendor/bin/psalm --use-baseline=psalm-baseline.xml"
],
"tests": [
"vendor/bin/phpunit --no-coverage"
......
......@@ -9,6 +9,7 @@ use League\OAuth2\Client\Provider\GenericResourceOwner;
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use League\OAuth2\Client\Token\AccessToken;
use Psr\Http\Message\ResponseInterface;
use SimpleSAML\Configuration;
use SimpleSAML\Logger;
class OpenIDConnectProvider extends AbstractProvider
......@@ -24,9 +25,9 @@ class OpenIDConnectProvider extends AbstractProvider
protected string $issuer;
/**
* @var ?array
* @var ?Configuration
*/
private ?array $openIdConfiguration = null;
private ?Configuration $openIdConfiguration = null;
/**
* @var string
......@@ -42,15 +43,14 @@ class OpenIDConnectProvider extends AbstractProvider
{
parent::__construct($options, $collaborators);
if (!array_key_exists('issuer', $options)) {
throw new \InvalidArgumentException(
'Required options not defined: issuer'
);
}
$this->issuer = $options['issuer'];
$this->defaultScopes = $options['scopes'] ?? ['openid', 'profile'];
$optionsConfig = Configuration::loadFromArray($options);
$this->issuer = $optionsConfig->getString('issuer');
$this->defaultScopes = $optionsConfig->getOptionalArray('scopes', ['openid', 'profile']);
}
/**
* {@inheritdoc}
*/
protected function getScopeSeparator()
{
return ' ';
......@@ -114,13 +114,14 @@ class OpenIDConnectProvider extends AbstractProvider
return $result;
}
protected function getOpenIDConfiguration(): array
protected function getOpenIDConfiguration(): Configuration
{
if (isset($this->openIdConfiguration)) {
return $this->openIdConfiguration;
}
$req = $this->getRequest('GET', rtrim($this->issuer, '/') . self::CONFIGURATION_PATH);
/** @var array $config */
$config = $this->getParsedResponse($req);
$requiredEndPoints = [ "authorization_endpoint", "token_endpoint", "jwks_uri", "issuer", "userinfo_endpoint" ];
foreach ($requiredEndPoints as $key) {
......@@ -152,8 +153,8 @@ class OpenIDConnectProvider extends AbstractProvider
}
}
}
$this->openIdConfiguration = $config;
return $config;
$this->openIdConfiguration = Configuration::loadFromArray($config);
return $this->openIdConfiguration;
}
/**
......@@ -167,12 +168,15 @@ class OpenIDConnectProvider extends AbstractProvider
protected function getSigningKeys(): array
{
$url = $this->getOpenIDConfiguration()['jwks_uri'];
$url = $this->getOpenIDConfiguration()->getString('jwks_uri');
/** @var array $jwks */
$jwks = $this->getParsedResponse($this->getRequest('GET', $url));
$keys = [];
foreach ($jwks['keys'] as $key) {
/** @var string $kid */
$kid = $key['kid'];
if (array_key_exists('x5c', $key)) {
/** @var array $x5c */
$x5c = $key['x5c'];
$keys[$kid] = "-----BEGIN CERTIFICATE-----\n" . $x5c[0] . "\n-----END CERTIFICATE-----";
} elseif ($key['kty'] === 'RSA') {
......@@ -199,7 +203,7 @@ class OpenIDConnectProvider extends AbstractProvider
*/
public function getBaseAuthorizationUrl()
{
return $this->getOpenIDConfiguration()["authorization_endpoint"];
return $this->getOpenIDConfiguration()->getString("authorization_endpoint");
}
/**
......@@ -212,26 +216,20 @@ class OpenIDConnectProvider extends AbstractProvider
*/
public function getBaseAccessTokenUrl(array $params)
{
return $this->getOpenIDConfiguration()["token_endpoint"];
return $this->getOpenIDConfiguration()->getString("token_endpoint");
}
/**
* Returns the URL for requesting the resource owner's details.
*
* @param AccessToken $token
* @return string
* {@inheritDoc}
*/
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return $this->getOpenIDConfiguration()["userinfo_endpoint"];
return $this->getOpenIDConfiguration()->getString("userinfo_endpoint");
}
public function getEndSessionEndpoint(): ?string
{
$config = $this->getOpenIDConfiguration();
if (array_key_exists("end_session_endpoint", $config)) {
return $config["end_session_endpoint"];
}
return null;
return $config->getOptionalString("end_session_endpoint", null);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.30.0@d0bc6e25d89f649e4f36a534f330f8bb4643dd69">
<file src="lib/AttributeManipulator.php">
<MixedArgument occurrences="1">
<code>$input</code>
</MixedArgument>
<MixedAssignment occurrences="3">
<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>
</MixedArrayAccess>
<MixedArrayAssignment occurrences="1">
<code>$state['Attributes'][$prefix . 'email']</code>
</MixedArrayAssignment>
<MixedAssignment occurrences="1">
<code>$response</code>
</MixedAssignment>
</file>
<file src="lib/Auth/Source/LinkedInV2Auth.php">
<MixedArgument occurrences="1">
<code>$attributes[$attributeName]['localized']</code>
</MixedArgument>
<MixedArrayAccess occurrences="1">
<code>$response["elements"][0]["handle~"]["emailAddress"]</code>
</MixedArrayAccess>
<MixedArrayAssignment occurrences="1">
<code>$state['Attributes'][$prefix . 'emailAddress']</code>
</MixedArrayAssignment>
<MixedAssignment occurrences="1">
<code>$response</code>
</MixedAssignment>
<MixedInferredReturnType occurrences="1">
<code>string|false|null</code>
</MixedInferredReturnType>
<MixedReturnStatement occurrences="1">
<code>reset($attributes[$attributeName]['localized'])</code>
</MixedReturnStatement>
</file>
<file src="lib/Auth/Source/MicrosoftHybridAuth.php">
<MixedArgument occurrences="1">
<code>$accessToken-&gt;getValues()['id_token']</code>
</MixedArgument>
<MixedArrayAssignment occurrences="2">
<code>$state['Attributes'][$prefix . 'mail']</code>
<code>$state['Attributes'][$prefix . 'name']</code>
</MixedArrayAssignment>
</file>
<file src="lib/Auth/Source/OAuth2.php">
<MixedArgument occurrences="7">
<code>$apiAttributes</code>
<code>$apiUrl</code>
<code>$config['urlResourceOwnerDetails']</code>
<code>$config['urlResourceOwnerOptions']</code>
<code>$idToken</code>
<code>$state['Attributes']</code>
<code>$templateArray</code>
</MixedArgument>
<MixedArgumentTypeCoercion occurrences="1"/>
<MixedArrayAccess occurrences="1">
<code>$templateArray[0]</code>
</MixedArrayAccess>
<MixedAssignment occurrences="6">
<code>$apiAttributes</code>
<code>$apiUrl</code>
<code>$data</code>
<code>$idToken</code>
<code>$template</code>
<code>$templateArray</code>
</MixedAssignment>
<MixedInferredReturnType occurrences="2">
<code>array</code>
<code>string[]</code>
</MixedInferredReturnType>
<MixedReturnStatement occurrences="2">
<code>$data</code>
<code>$provider-&gt;getParsedResponse($apiRequest)</code>
</MixedReturnStatement>
</file>
<file src="lib/Auth/Source/OpenIDConnect.php">
<MixedArgument occurrences="3">
<code>$handler</code>
<code>$id_token</code>
<code>$state['Attributes']</code>
</MixedArgument>
<MixedArgumentTypeCoercion occurrences="2">
<code>$key</code>
<code>$key</code>
</MixedArgumentTypeCoercion>
<MixedArrayAssignment occurrences="2">
<code>$httpClient-&gt;getConfig()['handler']</code>
<code>$state['PersistentAuthData'][]</code>
</MixedArrayAssignment>
<MixedAssignment occurrences="5">
<code>$handler</code>
<code>$id_token</code>
<code>$id_token</code>
<code>$result[substr($key, 5)]</code>
<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>
<code>$state['Attributes'][$prefix . 'sub']</code>
</MixedArrayAccess>
<MixedArrayAssignment occurrences="1">
<code>$state['Attributes'][$prefix . 'email']</code>
</MixedArrayAssignment>
<MixedAssignment occurrences="3">
<code>$e</code>
<code>$email</code>
<code>$response</code>
</MixedAssignment>
<MixedInferredReturnType occurrences="1">
<code>string</code>
</MixedInferredReturnType>
<MixedReturnStatement occurrences="1">
<code>$email</code>
</MixedReturnStatement>
</file>
<file src="lib/OAuth2ResponseHandler.php">
<MixedArgument occurrences="4">
<code>$request['code']</code>
<code>$sourceId</code>
<code>$stateIdWithPrefix</code>
<code>@$request['state']</code>
</MixedArgument>
<MixedAssignment occurrences="3">
<code>$error</code>
<code>$sourceId</code>
<code>$stateIdWithPrefix</code>
</MixedAssignment>
<MixedOperand occurrences="3">
<code>$error</code>
<code>@$request['error_description']</code>
<code>@$request['error_description']</code>
</MixedOperand>
</file>
<file src="lib/OIDCLogoutHandler.php">
<MixedArgument occurrences="4">
<code>$sourceId</code>
<code>$sourceId</code>
<code>$stateIdWithPrefix</code>
<code>@$request['state']</code>
</MixedArgument>
<MixedAssignment occurrences="3">
<code>$sourceId</code>
<code>$sourceId</code>
<code>$stateIdWithPrefix</code>
</MixedAssignment>
</file>
<file src="lib/Providers/AdjustableGenericProvider.php">
<MixedAssignment occurrences="1">
<code>$toAdd[$param]</code>
</MixedAssignment>
</file>
<file src="lib/Providers/OpenIDConnectProvider.php">
<MixedArgument occurrences="6">
<code>$claims-&gt;aud</code>
<code>$claims-&gt;iss</code>
<code>$key</code>
<code>$key['e']</code>
<code>$key['n']</code>
<code>$result['id_token']</code>
</MixedArgument>
<MixedArrayAccess occurrences="5">
<code>$key['e']</code>
<code>$key['kid']</code>
<code>$key['kty']</code>
<code>$key['n']</code>
<code>$key['x5c']</code>
</MixedArrayAccess>
<MixedAssignment occurrences="2">
<code>$error</code>
<code>$key</code>
</MixedAssignment>
<MixedOperand occurrences="2">
<code>$config['issuer']</code>
<code>$x5c[0]</code>
</MixedOperand>
</file>
<file src="tests/config/authsources.php">
<UnusedVariable occurrences="1">
<code>$config</code>
</UnusedVariable>
</file>
<file src="tests/config/config.php">
<UnusedVariable occurrences="1">
<code>$config</code>
</UnusedVariable>
</file>
<file src="tests/config/ssp2_0-config.php">
<UnusedVariable occurrences="1">
<code>$config</code>
</UnusedVariable>
</file>
<file src="tests/lib/AttributeManipulatorTest.php">
<MissingReturnType occurrences="1">
<code>testPrefixAndFlatten</code>
</MissingReturnType>
</file>
<file src="tests/lib/Auth/Source/LinkedInV2AuthTest.php">
<MissingReturnType occurrences="3">
<code>getEmailProvider</code>
<code>testAttributeConversion</code>
<code>testGettingEmail</code>
</MissingReturnType>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
<MixedMethodCall occurrences="5">
<code>method</code>
<code>willReturn</code>
<code>willReturn</code>
<code>with</code>
<code>with</code>
</MixedMethodCall>
<PossiblyInvalidArgument occurrences="2">
<code>$mock</code>
<code>$mock</code>
</PossiblyInvalidArgument>
<PossiblyUndefinedMethod occurrences="3">
<code>expects</code>
<code>method</code>
<code>method</code>
</PossiblyUndefinedMethod>
</file>
<file src="tests/lib/Auth/Source/MicrosoftHybridAuthTest.php">
<MissingReturnType occurrences="2">
<code>combineOidcAndGraphProfileProvider</code>
<code>testCombineOidcAndGraphProfile</code>
</MissingReturnType>
<MixedMethodCall occurrences="8">
<code>willReturn</code>
<code>willReturn</code>
<code>willReturn</code>
<code>willReturn</code>
<code>with</code>
<code>with</code>
<code>with</code>
<code>with</code>
</MixedMethodCall>
<PossiblyInvalidArgument occurrences="1">
<code>$mock</code>
</PossiblyInvalidArgument>
<PossiblyUndefinedMethod occurrences="4">
<code>method</code>
<code>method</code>
<code>method</code>
<code>method</code>
</PossiblyUndefinedMethod>
</file>
<file src="tests/lib/Auth/Source/OAuth2Test.php">
<DeprecatedMethod occurrences="1">
<code>getConfig</code>
</DeprecatedMethod>
<MissingParamType occurrences="15">
<code>$accessToken</code>
<code>$accessToken</code>
<code>$accessToken</code>
<code>$accessToken</code>
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$expectedAttributes</code>
<code>$expectedAttributes</code>
<code>$expectedAttributes</code>
<code>$expectedAttributes</code>
<code>$expectedUrl</code>
<code>$state</code>
</MissingParamType>
<MissingPropertyType occurrences="1">
<code>$module_config</code>
</MissingPropertyType>
<MissingReturnType occurrences="12">
<code>finalStepsDataProvider</code>
<code>finalStepsDataProviderWithAuthenticatedApiRequest</code>
<code>testAuthenticatePerformsRedirect</code>
<code>testConfigTemplateByName</code>
<code>testDefaultConfigItemsSet</code>
<code>testEnableDebugLogging</code>
<code>testFinalSteps</code>
<code>testFinalStepsWithAuthenticatedApiRequest</code>
<code>testFinalStepsWithAuthenticatedApiRequestWithNetworkErrors</code>
<code>testFinalStepsWithNetworkErrorsAndRetries</code>
<code>testResourceOwnerQueryParamOption</code>
<code>testTooManyErrorsForRetry</code>
</MissingReturnType>
<MixedArgument occurrences="7">
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$config</code>
<code>$expectedUrl</code>
<code>$state</code>
</MixedArgument>
<MixedArrayAccess occurrences="2">
<code>$clientConfig['handler']</code>
<code>$state[OAuth2::AUTHID]</code>
</MixedArrayAccess>
<MixedAssignment occurrences="1">
<code>$clientConfig</code>
</MixedAssignment>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
<MixedMethodCall occurrences="6">
<code>will</code>
<code>will</code>
<code>will</code>
<code>with</code>
<code>with</code>
<code>with</code>
</MixedMethodCall>
<PossiblyInvalidArgument occurrences="7">
<code>$mock</code>
<code>$mock</code>
<code>$mockRequest</code>
<code>$mockRequest</code>
<code>$mockRequest</code>
<code>$mockRequest</code>
<code>$mockRequest</code>
</PossiblyInvalidArgument>
<PossiblyUndefinedMethod occurrences="3">
<code>method</code>
<code>method</code>
<code>method</code>
</PossiblyUndefinedMethod>
</file>
<file src="tests/lib/Auth/Source/OpenIDConnectTest.php">
<MissingReturnType occurrences="3">
<code>testLogoutNoEndpointConfigured</code>
<code>testLogoutNoIDTokenInState</code>
<code>testLogoutRedirects</code>
</MissingReturnType>
</file>
<file src="tests/lib/Auth/Source/OrcidOIDCAuthTest.php">
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
</file>
<file src="tests/lib/MockOAuth2Provider.php">
<MissingReturnType occurrences="1">
<code>setDelegate</code>
</MissingReturnType>
</file>
<file src="tests/lib/MockOpenIDConnectProvider.php">
<MissingReturnType occurrences="2">
<code>setConfig</code>
<code>setSigningKeys</code>
</MissingReturnType>
</file>
<file src="tests/lib/OAuth2ResponseHandlerTest.php">
<MissingParamType occurrences="3">
<code>$expectedException</code>
<code>$expectedMessage</code>
<code>$queryParams</code>
</MissingParamType>
<MissingPropertyType occurrences="1">
<code>$validStateValue</code>
</MissingPropertyType>
<MissingReturnType occurrences="8">
<code>noCodeDataProvider</code>
<code>testCanHandle</code>
<code>testNoCodeInResponse</code>
<code>testNoStateFoundInSession</code>
<code>testSanityCheckMocks</code>
<code>testUnhandleableResponse</code>
<code>testUserCancelledErrorPage</code>
<code>testValidResponse</code>
</MissingReturnType>
<MixedArgument occurrences="3">
<code>$expectedException</code>
<code>$expectedMessage</code>
<code>$queryParams</code>
</MixedArgument>
<MixedMethodCall occurrences="8">
<code>method</code>
<code>method</code>
<code>method</code>
<code>willReturn</code>
<code>willReturn</code>
<code>with</code>
<code>with</code>
<code>with</code>
</MixedMethodCall>
<PossiblyUndefinedMethod occurrences="6">
<code>expects</code>
<code>expects</code>
<code>expects</code>
<code>finalStep</code>
<code>method</code>
<code>method</code>
</PossiblyUndefinedMethod>
</file>
<file src="tests/lib/OIDCLogoutHandlerTest.php">
<MissingReturnType occurrences="4">
<code>testCanHandle</code>
<code>testNoStateFoundInSession</code>
<code>testUnhandleableResponse</code>
<code>testValidResponse</code>
</MissingReturnType>
<MixedMethodCall occurrences="1">
<code>method</code>
</MixedMethodCall>
<PossiblyUndefinedMethod occurrences="1">
<code>expects</code>
</PossiblyUndefinedMethod>
</file>
<file src="tests/lib/Providers/AdjustableGenericProviderTest.php">
<MissingParamType occurrences="1">
<code>$expectedQueryString</code>
</MissingParamType>
<MissingReturnType occurrences="2">
<code>testNoAdjustmentsToUrl</code>
<code>testSetScopes</code>
</MissingReturnType>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
</file>
<file src="tests/lib/Providers/OpenIDConnectProviderTest.php">
<MissingParamType occurrences="2">
<code>$expectedMessage</code>
<code>$idToken</code>
</MissingParamType>
<MixedArgument occurrences="2">
<code>$expectedMessage</code>
<code>$idToken</code>
</MixedArgument>
<MixedInferredReturnType occurrences="1">
<code>array</code>
</MixedInferredReturnType>
<PossiblyFalseOperand occurrences="1">
<code>getenv('SIMPLESAMLPHP_CONFIG_DIR')</code>
</PossiblyFalseOperand>
</file>
</files>
<?xml version="1.0"?>
<psalm
errorLevel="2"
errorLevel="1"
hideExternalErrors="true"
resolveFromConfigFile="true"
autoloader="vendor/autoload.php"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorBaseline="psalm-baseline.xml"
>
<projectFiles>
<directory name="lib"/>
......
......@@ -2,20 +2,18 @@
namespace Test\SimpleSAML;
use SimpleSAML\Configuration;
use SimpleSAML\Module\authoauth2\Providers\OpenIDConnectProvider;
class MockOpenIDConnectProvider extends OpenIDConnectProvider
{
/**
* @var array
*/
private static $config;
private static Configuration $config;
private static $keys;
private static array $keys;
public static function setConfig(array $config)
{
self::$config = $config;
self::$config = Configuration::loadFromArray($config);
}
public static function setSigningKeys(array $keys)
......@@ -23,12 +21,12 @@ class MockOpenIDConnectProvider extends OpenIDConnectProvider
self::$keys = $keys;
}
protected function getOpenIDConfiguration()
protected function getOpenIDConfiguration(): Configuration
{
return self::$config;
}
protected function getSigningKeys()
protected function getSigningKeys(): array
{
return self::$keys;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment