diff --git a/CHANGELOG.md b/CHANGELOG.md index ec4bedb3a..28dba190e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Basic authorization is now case insensitive (PR #1403) +### Changed +- Request parameters are now parsed into strings to use internally in the library (PR #1402) + ## [9.0.0-RC1] - released 2024-03-27 ### Added - Device Authorization Grant added (PR #1074) diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php index 00d038462..b5648688e 100644 --- a/examples/src/Entities/UserEntity.php +++ b/examples/src/Entities/UserEntity.php @@ -19,8 +19,8 @@ class UserEntity implements UserEntityInterface /** * Return the user's identifier. */ - public function getIdentifier(): mixed + public function getIdentifier(): string { - return 1; + return '1'; } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 01f95f02b..6e471456d 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -14,6 +14,8 @@ tests examples + examples/vendor/* + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7bef99433..7949ac1d8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,8 +2,4 @@ parameters: level: 8 paths: - src - - tests - ignoreErrors: - - - message: '#Call to an undefined method League\\OAuth2\\Server\\ResponseTypes\\ResponseTypeInterface::getAccessToken\(\)\.#' - path: tests/Grant/ClientCredentialsGrantTest.php + - tests \ No newline at end of file diff --git a/src/CryptKey.php b/src/CryptKey.php index 944c56a05..3e1285f91 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -43,13 +43,13 @@ class CryptKey implements CryptKeyInterface public function __construct(string $keyPath, protected ?string $passPhrase = null, bool $keyPermissionsCheck = true) { - if (strpos($keyPath, self::FILE_PREFIX) !== 0 && $this->isValidKey($keyPath, $this->passPhrase ?? '')) { + if (str_starts_with($keyPath, self::FILE_PREFIX) === false && $this->isValidKey($keyPath, $this->passPhrase ?? '')) { $this->keyContents = $keyPath; $this->keyPath = ''; // There's no file, so no need for permission check. $keyPermissionsCheck = false; } elseif (is_file($keyPath)) { - if (strpos($keyPath, self::FILE_PREFIX) !== 0) { + if (str_starts_with($keyPath, self::FILE_PREFIX) === false) { $keyPath = self::FILE_PREFIX . $keyPath; } diff --git a/src/Entities/RefreshTokenEntityInterface.php b/src/Entities/RefreshTokenEntityInterface.php index f377cd9e1..79a99f24c 100644 --- a/src/Entities/RefreshTokenEntityInterface.php +++ b/src/Entities/RefreshTokenEntityInterface.php @@ -18,13 +18,17 @@ interface RefreshTokenEntityInterface { /** * Get the token's identifier. + * + * @return non-empty-string */ public function getIdentifier(): string; /** * Set the token's identifier. + * + * @param non-empty-string $identifier */ - public function setIdentifier(mixed $identifier): void; + public function setIdentifier(string $identifier): void; /** * Get the token's expiry date time. diff --git a/src/Entities/ScopeEntityInterface.php b/src/Entities/ScopeEntityInterface.php index 37c40bf55..6546d61ac 100644 --- a/src/Entities/ScopeEntityInterface.php +++ b/src/Entities/ScopeEntityInterface.php @@ -18,6 +18,8 @@ interface ScopeEntityInterface extends JsonSerializable { /** * Get the scope's identifier. + * + * @return non-empty-string */ public function getIdentifier(): string; } diff --git a/src/Entities/TokenInterface.php b/src/Entities/TokenInterface.php index 96d2bd418..b9d5c270f 100644 --- a/src/Entities/TokenInterface.php +++ b/src/Entities/TokenInterface.php @@ -18,13 +18,17 @@ interface TokenInterface { /** * Get the token's identifier. + * + * @return non-empty-string */ public function getIdentifier(): string; /** * Set the token's identifier. + * + * @param non-empty-string $identifier */ - public function setIdentifier(mixed $identifier): void; + public function setIdentifier(string $identifier): void; /** * Get the token's expiry date time. @@ -45,8 +49,10 @@ public function setUserIdentifier(string $identifier): void; /** * Get the token user's identifier. + * + * @return non-empty-string|null */ - public function getUserIdentifier(): string|int|null; + public function getUserIdentifier(): string|null; /** * Get the client that the token was issued to. diff --git a/src/Entities/Traits/DeviceCodeTrait.php b/src/Entities/Traits/DeviceCodeTrait.php index ea8b2acc2..125e7ef54 100644 --- a/src/Entities/Traits/DeviceCodeTrait.php +++ b/src/Entities/Traits/DeviceCodeTrait.php @@ -59,6 +59,9 @@ abstract public function getExpiryDateTime(): DateTimeImmutable; */ abstract public function getScopes(): array; + /** + * @return non-empty-string + */ abstract public function getIdentifier(): string; public function getLastPolledAt(): ?DateTimeImmutable diff --git a/src/Entities/Traits/EntityTrait.php b/src/Entities/Traits/EntityTrait.php index 87a8f6cf6..3634b5350 100644 --- a/src/Entities/Traits/EntityTrait.php +++ b/src/Entities/Traits/EntityTrait.php @@ -27,7 +27,10 @@ public function getIdentifier(): string return $this->identifier; } - public function setIdentifier(mixed $identifier): void + /** + * @param non-empty-string $identifier + */ + public function setIdentifier(string $identifier): void { $this->identifier = $identifier; } diff --git a/src/Entities/UserEntityInterface.php b/src/Entities/UserEntityInterface.php index ef88a84d2..0a678e735 100644 --- a/src/Entities/UserEntityInterface.php +++ b/src/Entities/UserEntityInterface.php @@ -16,6 +16,8 @@ interface UserEntityInterface { /** * Return the user's identifier. + * + * @return non-empty-string */ - public function getIdentifier(): mixed; + public function getIdentifier(): string; } diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 03950a381..f313967ad 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -269,9 +269,9 @@ public function generateHttpResponse(ResponseInterface $response, bool $useFragm if ($this->redirectUri !== null) { if ($useFragment === true) { - $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&'; + $this->redirectUri .= (str_contains($this->redirectUri, '#') === false) ? '#' : '&'; } else { - $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&'; + $this->redirectUri .= (str_contains($this->redirectUri, '?') === false) ? '?' : '&'; } return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload)); @@ -310,7 +310,7 @@ public function getHttpHeaders(): array // include the "WWW-Authenticate" response header field // matching the authentication scheme used by the client. if ($this->errorType === 'invalid_client' && $this->requestHasAuthorizationHeader()) { - $authScheme = strpos($this->serverRequest->getHeader('Authorization')[0], 'Bearer') === 0 ? 'Bearer' : 'Basic'; + $authScheme = str_starts_with($this->serverRequest->getHeader('Authorization')[0], 'Bearer') ? 'Bearer' : 'Basic'; $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"'; } diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 4fe552c17..22b58c4e2 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -18,16 +18,15 @@ use League\OAuth2\Server\RequestTypes\AuthorizationRequestInterface; use function http_build_query; -use function strstr; abstract class AbstractAuthorizeGrant extends AbstractGrant { /** - * @param mixed[] $params + * @param array $params */ public function makeRedirectUri(string $uri, array $params = [], string $queryDelimiter = '?'): string { - $uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&'; + $uri .= str_contains($uri, $queryDelimiter) ? '&' : $queryDelimiter; return $uri . http_build_query($params); } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 96a1fb65f..31252cc1e 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -49,10 +49,8 @@ use function base64_decode; use function bin2hex; use function explode; -use function is_null; use function is_string; use function random_bytes; -use function strpos; use function substr; use function trim; @@ -129,9 +127,9 @@ public function setRefreshTokenTTL(DateInterval $refreshTokenTTL): void /** * Set the private key */ - public function setPrivateKey(CryptKeyInterface $key): void + public function setPrivateKey(CryptKeyInterface $privateKey): void { - $this->privateKey = $key; + $this->privateKey = $privateKey; } public function setDefaultScope(string $scope): void @@ -139,9 +137,9 @@ public function setDefaultScope(string $scope): void $this->defaultScope = $scope; } - public function revokeRefreshTokens(bool $revokeRefreshTokens): void + public function revokeRefreshTokens(bool $willRevoke): void { - $this->revokeRefreshTokens = $revokeRefreshTokens; + $this->revokeRefreshTokens = $willRevoke; } /** @@ -161,13 +159,9 @@ protected function validateClient(ServerRequestInterface $request): ClientEntity $client = $this->getClientEntityOrFail($clientId, $request); // If a redirect URI is provided ensure it matches what is pre-registered - $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + $redirectUri = $this->getRequestParameter('redirect_uri', $request); if ($redirectUri !== null) { - if (!is_string($redirectUri)) { - throw OAuthServerException::invalidRequest('redirect_uri'); - } - $this->validateRedirectUri($redirectUri, $client, $request); } @@ -183,6 +177,8 @@ protected function validateClient(ServerRequestInterface $request): ClientEntity * doesn't actually enforce non-null returns/exception-on-no-client so * getClientEntity might return null. By contrast, this method will * always either return a ClientEntityInterface or throw. + * + * @throws OAuthServerException */ protected function getClientEntityOrFail(string $clientId, ServerRequestInterface $request): ClientEntityInterface { @@ -200,7 +196,8 @@ protected function getClientEntityOrFail(string $clientId, ServerRequestInterfac * Gets the client credentials from the request from the request body or * the Http Basic Authorization header * - * @return string[] + * @return array{0:non-empty-string,1:string} + * @throws OAuthServerException */ protected function getClientCredentials(ServerRequestInterface $request): array { @@ -208,17 +205,13 @@ protected function getClientCredentials(ServerRequestInterface $request): array $clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser); - if (is_null($clientId)) { + if ($clientId === null) { throw OAuthServerException::invalidRequest('client_id'); } $clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword); - if ($clientSecret !== null && !is_string($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret'); - } - - return [$clientId, $clientSecret]; + return [$clientId, $clientSecret ?? '']; } /** @@ -279,19 +272,47 @@ public function validateScopes(string|array|null $scopes, string $redirectUri = */ private function convertScopesQueryStringToArray(string $scopes): array { - return array_filter(explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), function ($scope) { - return $scope !== ''; - }); + return array_filter(explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), static fn($scope) => $scope !== ''); } /** - * Retrieve request parameter. + * Parse request parameter. + * + * @param array $request + * + * @return non-empty-string|null + * @throws OAuthServerException */ - protected function getRequestParameter(string $parameter, ServerRequestInterface $request, mixed $default = null): mixed + private static function parseParam(string $parameter, array $request, ?string $default = null): ?string { - $requestParameters = (array) $request->getParsedBody(); + $value = $request[$parameter] ?? ''; + + if (is_scalar($value)) { + $value = trim((string)$value); + } else { + throw OAuthServerException::invalidRequest($parameter); + } + + if ($value === '') { + $value = $default === null ? null : trim($default); + + if ($value === '') { + $value = null; + } + } - return $requestParameters[$parameter] ?? $default; + return $value; + } + + /** + * Retrieve request parameter. + * + * @return non-empty-string|null + * @throws OAuthServerException + */ + protected function getRequestParameter(string $parameter, ServerRequestInterface $request, ?string $default = null): ?string + { + return self::parseParam($parameter, (array) $request->getParsedBody(), $default); } /** @@ -301,7 +322,7 @@ protected function getRequestParameter(string $parameter, ServerRequestInterface * not exist, or is otherwise an invalid HTTP Basic header, return * [null, null]. * - * @return string[]|null[] + * @return array{0:non-empty-string,1:string}|array{0:null,1:null} */ protected function getBasicAuthCredentials(ServerRequestInterface $request): array { @@ -320,35 +341,50 @@ protected function getBasicAuthCredentials(ServerRequestInterface $request): arr return [null, null]; } - if (strpos($decoded, ':') === false) { + if (str_contains($decoded, ':') === false) { return [null, null]; // HTTP Basic header without colon isn't valid } - return explode(':', $decoded, 2); + [$username, $password] = explode(':', $decoded, 2); + + if ($username === '') { + return [null, null]; + } + + return [$username, $password]; } /** * Retrieve query string parameter. + * + * @return non-empty-string|null + * @throws OAuthServerException */ - protected function getQueryStringParameter(string $parameter, ServerRequestInterface $request, mixed $default = null): ?string + protected function getQueryStringParameter(string $parameter, ServerRequestInterface $request, ?string $default = null): ?string { - return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default; + return self::parseParam($parameter, $request->getQueryParams(), $default); } /** * Retrieve cookie parameter. + * + * @return non-empty-string|null + * @throws OAuthServerException */ - protected function getCookieParameter(string $parameter, ServerRequestInterface $request, mixed $default = null): ?string + protected function getCookieParameter(string $parameter, ServerRequestInterface $request, ?string $default = null): ?string { - return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default; + return self::parseParam($parameter, $request->getCookieParams(), $default); } /** * Retrieve server parameter. + * + * @return non-empty-string|null + * @throws OAuthServerException */ - protected function getServerParameter(string $parameter, ServerRequestInterface $request, mixed $default = null): ?string + protected function getServerParameter(string $parameter, ServerRequestInterface $request, ?string $default = null): ?string { - return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default; + return self::parseParam($parameter, $request->getServerParams(), $default); } /** @@ -362,7 +398,7 @@ protected function getServerParameter(string $parameter, ServerRequestInterface protected function issueAccessToken( DateInterval $accessTokenTTL, ClientEntityInterface $client, - string|int|null $userIdentifier, + string|null $userIdentifier, array $scopes = [] ): AccessTokenEntityInterface { $maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS; @@ -473,6 +509,8 @@ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken): ? /** * Generate a new unique identifier. * + * @return non-empty-string + * * @throws OAuthServerException */ protected function generateUniqueIdentifier(int $length = 40): string diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 83bddac18..8a24a8e95 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -41,7 +41,6 @@ use function implode; use function in_array; use function is_array; -use function is_string; use function json_decode; use function json_encode; use function preg_match; @@ -106,9 +105,9 @@ public function respondToAccessTokenRequest( $this->validateClient($request); } - $encryptedAuthCode = $this->getRequestParameter('code', $request, null); + $encryptedAuthCode = $this->getRequestParameter('code', $request); - if (!is_string($encryptedAuthCode)) { + if ($encryptedAuthCode === null) { throw OAuthServerException::invalidRequest('code'); } @@ -128,7 +127,7 @@ public function respondToAccessTokenRequest( throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code', $e); } - $codeVerifier = $this->getRequestParameter('code_verifier', $request, null); + $codeVerifier = $this->getRequestParameter('code_verifier', $request); // If a code challenge isn't present but a code verifier is, reject the request to block PKCE downgrade attack if (!isset($authCodePayload->code_challenge) && $codeVerifier !== null) { @@ -219,7 +218,7 @@ private function validateAuthorizationCode( } // The redirect URI is required in this request - $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + $redirectUri = $this->getRequestParameter('redirect_uri', $request); if ($authCodePayload->redirect_uri !== '' && $redirectUri === null) { throw OAuthServerException::invalidRequest('redirect_uri'); } diff --git a/src/Grant/DeviceCodeGrant.php b/src/Grant/DeviceCodeGrant.php index 89568a19b..3804e2027 100644 --- a/src/Grant/DeviceCodeGrant.php +++ b/src/Grant/DeviceCodeGrant.php @@ -153,10 +153,10 @@ public function respondToAccessTokenRequest( } // Finalize the requested scopes - $finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, (string) $deviceCodeEntity->getUserIdentifier()); + $finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $deviceCodeEntity->getUserIdentifier()); // Issue and persist new access token - $accessToken = $this->issueAccessToken($accessTokenTTL, $client, (string) $deviceCodeEntity->getUserIdentifier(), $finalizedScopes); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $deviceCodeEntity->getUserIdentifier(), $finalizedScopes); $this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request)); $responseType->setAccessToken($accessToken); @@ -304,9 +304,7 @@ protected function generateUserCode(int $length = 8): string return $userCode; // @codeCoverageIgnoreStart - } catch (TypeError $e) { - throw OAuthServerException::serverError('An unexpected error has occurred', $e); - } catch (Error $e) { + } catch (TypeError | Error $e) { throw OAuthServerException::serverError('An unexpected error has occurred', $e); } catch (Exception $e) { // If you get this message, the CSPRNG failed hard. diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 1b92dc1da..f5d8da322 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -26,8 +26,6 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; -use function is_string; - /** * Password grant class. */ @@ -84,17 +82,11 @@ public function respondToAccessTokenRequest( */ protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client): UserEntityInterface { - $username = $this->getRequestParameter('username', $request); - - if (!is_string($username)) { - throw OAuthServerException::invalidRequest('username'); - } + $username = $this->getRequestParameter('username', $request) + ?? throw OAuthServerException::invalidRequest('username'); - $password = $this->getRequestParameter('password', $request); - - if (!is_string($password)) { - throw OAuthServerException::invalidRequest('password'); - } + $password = $this->getRequestParameter('password', $request) + ?? throw OAuthServerException::invalidRequest('password'); $user = $this->userRepository->getUserEntityByUserCredentials( $username, diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 5a5b55e30..a632990c7 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -26,7 +26,6 @@ use function implode; use function in_array; -use function is_string; use function json_decode; use function time; @@ -53,6 +52,7 @@ public function respondToAccessTokenRequest( // Validate request $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); + $scopes = $this->validateScopes( $this->getRequestParameter( 'scope', @@ -102,10 +102,8 @@ public function respondToAccessTokenRequest( */ protected function validateOldRefreshToken(ServerRequestInterface $request, string $clientId): array { - $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request); - if (!is_string($encryptedRefreshToken)) { - throw OAuthServerException::invalidRequest('refresh_token'); - } + $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request) + ?? throw OAuthServerException::invalidRequest('refresh_token'); // Validate refresh token try { diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index d392716ed..8bac8be64 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -30,7 +30,7 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface public function getNewToken( ClientEntityInterface $clientEntity, array $scopes, - mixed $userIdentifier = null + string|null $userIdentifier = null ): AccessTokenEntityInterface; /** diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 95bfdbb9a..e5ae7c716 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -39,7 +39,7 @@ public function finalizeScopes( array $scopes, string $grantType, ClientEntityInterface $clientEntity, - string|int|null $userIdentifier = null, + string|null $userIdentifier = null, ?string $authCodeId = null ): array; } diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index c33bdc712..dd49b99ba 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -73,7 +73,7 @@ public function generateHttpResponse(ResponseInterface $response): ResponseInter * AuthorizationServer::getResponseType() to pull in your version of * this class rather than the default. * - * @return mixed[] + * @return array */ protected function getExtraParams(AccessTokenEntityInterface $accessToken): array { diff --git a/src/ResponseTypes/DeviceCodeResponse.php b/src/ResponseTypes/DeviceCodeResponse.php index 339c75bd3..91a8df69a 100644 --- a/src/ResponseTypes/DeviceCodeResponse.php +++ b/src/ResponseTypes/DeviceCodeResponse.php @@ -84,7 +84,7 @@ public function includeVerificationUriComplete(): void * AuthorizationServer::getResponseType() to pull in your version of * this class rather than the default. * - * @return mixed[] + * @return array */ protected function getExtraParams(DeviceCodeEntityInterface $deviceCode): array { diff --git a/tests/Exception/OAuthServerExceptionTest.php b/tests/Exception/OAuthServerExceptionTest.php index 27922b427..93db59f2a 100644 --- a/tests/Exception/OAuthServerExceptionTest.php +++ b/tests/Exception/OAuthServerExceptionTest.php @@ -123,7 +123,7 @@ public function testHasPrevious(): void $previous = new Exception('This is the previous'); $exceptionWithPrevious = OAuthServerException::accessDenied(null, null, $previous); - $previousMessage = $exceptionWithPrevious->getPrevious() !== null ? $exceptionWithPrevious->getPrevious()->getMessage() : null; + $previousMessage = $exceptionWithPrevious->getPrevious()?->getMessage(); self::assertSame('This is the previous', $previousMessage); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 4a3c1e935..6a6842661 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -602,7 +602,7 @@ public function testRespondToAccessTokenRequest(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -665,7 +665,7 @@ public function testRespondToAccessTokenRequestUsingHttpBasicAuth(): void 'auth_code_id' => uniqid(), 'client_id' => 'foo', 'expire_time' => time() + 3600, - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -730,7 +730,7 @@ public function testRespondToAccessTokenRequestForPublicClient(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -795,7 +795,7 @@ public function testRespondToAccessTokenRequestNullRefreshToken(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -867,7 +867,7 @@ public function testRespondToAccessTokenRequestCodeChallengePlain(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => self::CODE_VERIFIER, @@ -941,7 +941,7 @@ public function testRespondToAccessTokenRequestCodeChallengeS256(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => self::CODE_CHALLENGE, @@ -1013,7 +1013,7 @@ public function testPKCEDowngradeBlocked(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], @@ -1561,7 +1561,7 @@ public function testRespondToAccessTokenRequestBadCodeVerifierPlain(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => 'foobar', @@ -1636,7 +1636,7 @@ public function testRespondToAccessTokenRequestBadCodeVerifierS256(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => 'foobar', @@ -1711,7 +1711,7 @@ public function testRespondToAccessTokenRequestMalformedCodeVerifierS256WithInva 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => self::CODE_CHALLENGE, @@ -1786,7 +1786,7 @@ public function testRespondToAccessTokenRequestMalformedCodeVerifierS256WithInva 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => 'R7T1y1HPNFvs1WDCrx4lfoBS6KD2c71pr8OHvULjvv8', @@ -1860,7 +1860,7 @@ public function testRespondToAccessTokenRequestMissingCodeVerifier(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, 'code_challenge' => 'foobar', @@ -2034,7 +2034,7 @@ public function testRefreshTokenRepositoryUniqueConstraintCheck(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -2099,7 +2099,7 @@ public function testRefreshTokenRepositoryFailToPersist(): void 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) @@ -2167,7 +2167,7 @@ public function testRefreshTokenRepositoryFailToPersistUniqueNoInfiniteLoop(): v 'auth_code_id' => uniqid(), 'expire_time' => time() + 3600, 'client_id' => 'foo', - 'user_id' => 123, + 'user_id' => '123', 'scopes' => ['foo'], 'redirect_uri' => self::REDIRECT_URI, ], JSON_THROW_ON_ERROR) diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 264e026e2..69f756c37 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -59,6 +59,8 @@ public function testRespondToRequest(): void ]); $responseType = new StubResponseType(); + + /** @var StubResponseType $response */ $response = $grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M')); self::assertNotEmpty($response->getAccessToken()->getIdentifier()); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 515629247..c2b943197 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -23,6 +23,7 @@ use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use LogicException; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ImplicitGrantTest extends TestCase @@ -282,7 +283,7 @@ public function testAccessTokenRepositoryUniqueConstraintCheck(): void $accessToken->setClient($client); $accessToken->setUserIdentifier('userId'); - /** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */ + /** @var AccessTokenRepositoryInterface|MockObject $accessTokenRepositoryMock */ $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('getNewToken')->willReturn($accessToken); @@ -321,7 +322,7 @@ public function testAccessTokenRepositoryFailToPersist(): void $authRequest->setGrantTypeId('authorization_code'); $authRequest->setUser(new UserEntity()); - /** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */ + /** @var AccessTokenRepositoryInterface|MockObject $accessTokenRepositoryMock */ $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(OAuthServerException::serverError('something bad happened')); @@ -353,7 +354,7 @@ public function testAccessTokenRepositoryFailToPersistUniqueNoInfiniteLoop(): vo $authRequest->setGrantTypeId('authorization_code'); $authRequest->setUser(new UserEntity()); - /** @var AccessTokenRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject $accessTokenRepositoryMock */ + /** @var AccessTokenRepositoryInterface|MockObject $accessTokenRepositoryMock */ $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create()); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 747ba5ead..b37001a80 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -80,7 +80,7 @@ public function testRespondToRequest(): void 'refresh_token_id' => 'zyxwvu', 'access_token_id' => 'abcdef', 'scopes' => ['foo'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -144,7 +144,7 @@ public function testRespondToRequestNullRefreshToken(): void 'refresh_token_id' => 'zyxwvu', 'access_token_id' => 'abcdef', 'scopes' => ['foo'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -208,7 +208,7 @@ public function testRespondToReducedScopes(): void 'refresh_token_id' => 'zyxwvu', 'access_token_id' => 'abcdef', 'scopes' => ['foo', 'bar'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -578,7 +578,7 @@ public function testRespondToRequestFinalizeScopes(): void 'refresh_token_id' => 'zyxwvu', 'access_token_id' => 'abcdef', 'scopes' => ['foo', 'bar'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -595,7 +595,7 @@ public function testRespondToRequestFinalizeScopes(): void 'client_id' => 'foo', 'client_secret' => 'bar', 'refresh_token' => $encryptedOldRefreshToken, - 'scope' => ['foo', 'bar'], + 'scope' => 'foo bar', ]); $responseType = new StubResponseType(); @@ -637,7 +637,7 @@ public function testRevokedRefreshToken(): void 'refresh_token_id' => $refreshTokenId, 'access_token_id' => 'abcdef', 'scopes' => ['foo'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -654,7 +654,7 @@ public function testRevokedRefreshToken(): void 'client_id' => 'foo', 'client_secret' => 'bar', 'refresh_token' => $encryptedOldRefreshToken, - 'scope' => ['foo'], + 'scope' => 'foo', ]); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); @@ -702,7 +702,7 @@ public function testUnrevokedRefreshToken(): void 'refresh_token_id' => $refreshTokenId, 'access_token_id' => 'abcdef', 'scopes' => ['foo'], - 'user_id' => 123, + 'user_id' => '123', 'expire_time' => time() + 3600, ] ); @@ -719,7 +719,7 @@ public function testUnrevokedRefreshToken(): void 'client_id' => 'foo', 'client_secret' => 'bar', 'refresh_token' => $encryptedOldRefreshToken, - 'scope' => ['foo'], + 'scope' => 'foo', ]); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 0f8f371a1..02f6f14e8 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -35,7 +35,7 @@ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken): void } /** - * @throws \League\OAuth2\Server\Exception\OAuthServerException + * @throws OAuthServerException */ public function validateAccessToken(ServerRequestInterface $request): ServerRequestInterface {