From 3bba99a7577a3410fef0e508665f250888babae2 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Thu, 9 Jan 2025 05:23:41 +0500 Subject: [PATCH] fix: use custom Redirect URI validation logic in RefreshTokenGrant (#42) Co-authored-by: ErickSkrauch --- .../OAuth2/Grants/AuthCodeGrant.php | 32 ++--------------- .../Grants/CheckOfflineAccessScopeTrait.php | 26 ++++++++++++++ .../OAuth2/Grants/DeviceCodeGrant.php | 10 ++---- .../OAuth2/Grants/RefreshTokenGrant.php | 1 + .../Grants/ValidateRedirectUriTrait.php | 34 +++++++++++++++++++ 5 files changed, 66 insertions(+), 37 deletions(-) create mode 100644 common/components/OAuth2/Grants/CheckOfflineAccessScopeTrait.php create mode 100644 common/components/OAuth2/Grants/ValidateRedirectUriTrait.php diff --git a/common/components/OAuth2/Grants/AuthCodeGrant.php b/common/components/OAuth2/Grants/AuthCodeGrant.php index 9dd7031..0d16292 100644 --- a/common/components/OAuth2/Grants/AuthCodeGrant.php +++ b/common/components/OAuth2/Grants/AuthCodeGrant.php @@ -4,19 +4,15 @@ declare(strict_types=1); namespace common\components\OAuth2\Grants; use common\components\OAuth2\CryptTrait; -use common\components\OAuth2\Events\RequestedRefreshToken; -use common\components\OAuth2\Repositories\PublicScopeRepository; use DateInterval; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant as BaseAuthCodeGrant; -use League\OAuth2\Server\RequestEvent; -use Psr\Http\Message\ServerRequestInterface; -use yii\helpers\StringHelper; final class AuthCodeGrant extends BaseAuthCodeGrant { use CryptTrait; + use CheckOfflineAccessScopeTrait; + use ValidateRedirectUriTrait; protected function issueAccessToken( DateInterval $accessTokenTTL, @@ -24,30 +20,8 @@ final class AuthCodeGrant extends BaseAuthCodeGrant { ?string $userIdentifier, array $scopes = [], ): AccessTokenEntityInterface { - foreach ($scopes as $i => $scope) { - if ($scope->getIdentifier() === PublicScopeRepository::OFFLINE_ACCESS) { - unset($scopes[$i]); - $this->getEmitter()->emit(new RequestedRefreshToken('refresh_token_requested')); - } - } - + $this->checkOfflineAccessScope($scopes); return parent::issueAccessToken($accessTokenTTL, $client, $userIdentifier, $scopes); } - protected function validateRedirectUri( - string $redirectUri, - ClientEntityInterface $client, - ServerRequestInterface $request, - ): void { - $allowedRedirectUris = (array)$client->getRedirectUri(); - foreach ($allowedRedirectUris as $allowedRedirectUri) { - if (StringHelper::startsWith($redirectUri, $allowedRedirectUri)) { - return; - } - } - - $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request)); - throw OAuthServerException::invalidClient($request); - } - } diff --git a/common/components/OAuth2/Grants/CheckOfflineAccessScopeTrait.php b/common/components/OAuth2/Grants/CheckOfflineAccessScopeTrait.php new file mode 100644 index 0000000..12a1b18 --- /dev/null +++ b/common/components/OAuth2/Grants/CheckOfflineAccessScopeTrait.php @@ -0,0 +1,26 @@ + $scope) { + if ($scope->getIdentifier() === PublicScopeRepository::OFFLINE_ACCESS) { + unset($scopes[$i]); + $this->getEmitter()->emit(new RequestedRefreshToken('refresh_token_requested')); + } + } + } + +} diff --git a/common/components/OAuth2/Grants/DeviceCodeGrant.php b/common/components/OAuth2/Grants/DeviceCodeGrant.php index b4d154e..994a6aa 100644 --- a/common/components/OAuth2/Grants/DeviceCodeGrant.php +++ b/common/components/OAuth2/Grants/DeviceCodeGrant.php @@ -3,9 +3,7 @@ declare(strict_types=1); namespace common\components\OAuth2\Grants; -use common\components\OAuth2\Events\RequestedRefreshToken; use common\components\OAuth2\Repositories\ExtendedDeviceCodeRepositoryInterface; -use common\components\OAuth2\Repositories\PublicScopeRepository; use common\components\OAuth2\ResponseTypes\EmptyResponse; use DateInterval; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; @@ -22,6 +20,7 @@ use Psr\Http\Message\ServerRequestInterface; * @property ExtendedDeviceCodeRepositoryInterface $deviceCodeRepository */ final class DeviceCodeGrant extends BaseDeviceCodeGrant { + use CheckOfflineAccessScopeTrait; public function __construct( ExtendedDeviceCodeRepositoryInterface $deviceCodeRepository, @@ -95,12 +94,7 @@ final class DeviceCodeGrant extends BaseDeviceCodeGrant { ?string $userIdentifier, array $scopes = [], ): AccessTokenEntityInterface { - foreach ($scopes as $i => $scope) { - if ($scope->getIdentifier() === PublicScopeRepository::OFFLINE_ACCESS) { - unset($scopes[$i]); - $this->getEmitter()->emit(new RequestedRefreshToken('refresh_token_requested')); - } - } + $this->checkOfflineAccessScope($scopes); return parent::issueAccessToken($accessTokenTTL, $client, $userIdentifier, $scopes); } diff --git a/common/components/OAuth2/Grants/RefreshTokenGrant.php b/common/components/OAuth2/Grants/RefreshTokenGrant.php index 6b5d3d4..b60c74d 100644 --- a/common/components/OAuth2/Grants/RefreshTokenGrant.php +++ b/common/components/OAuth2/Grants/RefreshTokenGrant.php @@ -20,6 +20,7 @@ use Yii; final class RefreshTokenGrant extends BaseRefreshTokenGrant { use CryptTrait; + use ValidateRedirectUriTrait; /** * Previously, refresh tokens were stored in Redis. diff --git a/common/components/OAuth2/Grants/ValidateRedirectUriTrait.php b/common/components/OAuth2/Grants/ValidateRedirectUriTrait.php new file mode 100644 index 0000000..d9e7dd3 --- /dev/null +++ b/common/components/OAuth2/Grants/ValidateRedirectUriTrait.php @@ -0,0 +1,34 @@ +getRedirectUri(); + foreach ($allowedRedirectUris as $allowedRedirectUri) { + if (StringHelper::startsWith($redirectUri, $allowedRedirectUri)) { + return; + } + } + + $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request)); + + throw OAuthServerException::invalidClient($request); + } + +}