From 9a6715e98c46df9e69a9569165ddaef9a8e9bc26 Mon Sep 17 00:00:00 2001 From: NikaS Date: Tue, 3 Sep 2024 15:28:23 +0400 Subject: [PATCH 1/4] When emulated user requests new access token. set emulator user id. --- .../Grants/InternalRefreshTokenGrant.php | 80 +++++++++++++++++++ .../Auth/Passport/PassportServiceProvider.php | 9 ++- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php index ff77629..d7ae13f 100644 --- a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php +++ b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php @@ -4,21 +4,101 @@ namespace Longman\LaravelLodash\Auth\Passport\Grants; +use DateInterval; +use Laravel\Passport\TokenRepository; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\RequestAccessTokenEvent; use League\OAuth2\Server\RequestEvent; +use League\OAuth2\Server\RequestRefreshTokenEvent; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use Longman\LaravelLodash\Auth\Contracts\AuthServiceContract; use Psr\Http\Message\ServerRequestInterface; +use function implode; +use function in_array; use function is_null; class InternalRefreshTokenGrant extends RefreshTokenGrant { + private readonly TokenRepository $tokenRepository; + private readonly AuthServiceContract $authService; + + public function __construct( + RefreshTokenRepositoryInterface $refreshTokenRepository, + TokenRepository $tokenRepository, + AuthServiceContract $authService, + ) { + parent::__construct($refreshTokenRepository); + + $this->tokenRepository = $tokenRepository; + $this->authService = $authService; + } + public function getIdentifier(): string { return 'internal_refresh_token'; } + /** + * {@inheritdoc} + */ + public function respondToAccessTokenRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + DateInterval $accessTokenTTL, + ) { + // Validate request + $client = $this->validateClient($request); + $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); + $scopes = $this->validateScopes( + $this->getRequestParameter( + 'scope', + $request, + implode(self::SCOPE_DELIMITER_STRING, $oldRefreshToken['scopes']), + ), + ); + + // The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure + // the request doesn't include any new scopes + foreach ($scopes as $scope) { + if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes'], true) === false) { + throw OAuthServerException::invalidScope($scope->getIdentifier()); + } + } + + // Expire old tokens + $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); + if ($this->revokeRefreshTokens) { + $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); + } + + // Issue and persist new access token + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); + $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken)); + $responseType->setAccessToken($accessToken); + + // Issue and persist new refresh token if given + if ($this->revokeRefreshTokens) { + $refreshToken = $this->issueRefreshToken($accessToken); + + if ($refreshToken !== null) { + $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken)); + $responseType->setRefreshToken($refreshToken); + } + } + + // when emulated user requests mew access token. set emulator user id. + $oldAccessToken = $this->tokenRepository->find($oldRefreshToken['access_token_id']); + if ($oldAccessToken->emulator_user_id) { + $this->authService->updateAccessToken($accessToken->getIdentifier(), $oldAccessToken->emulator_user_id); + } + + return $responseType; + } + protected function validateClient(ServerRequestInterface $request): ClientEntityInterface { [$basicAuthUser,] = $this->getBasicAuthCredentials($request); diff --git a/src/Lodash/Auth/Passport/PassportServiceProvider.php b/src/Lodash/Auth/Passport/PassportServiceProvider.php index e51d81f..8250f13 100644 --- a/src/Lodash/Auth/Passport/PassportServiceProvider.php +++ b/src/Lodash/Auth/Passport/PassportServiceProvider.php @@ -9,6 +9,7 @@ use Laravel\Passport\Passport; use Laravel\Passport\PassportServiceProvider as BasePassportServiceProvider; use Laravel\Passport\PassportUserProvider; +use Laravel\Passport\TokenRepository as PassportTokenRepository; use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\ResourceServer; use Longman\LaravelLodash\Auth\Contracts\AuthServiceContract; @@ -104,9 +105,11 @@ protected function makeInternalGrant(): InternalGrant protected function makeInternalRefreshTokenGrant(): InternalRefreshTokenGrant { - $repository = $this->app->make(RefreshTokenBridgeRepositoryContract::class); - - $grant = new InternalRefreshTokenGrant($repository); + $grant = new InternalRefreshTokenGrant( + $this->app->make(RefreshTokenBridgeRepositoryContract::class), + $this->app->make(PassportTokenRepository::class), + $this->app->make(AuthServiceContract::class), + ); $grant->setRefreshTokenTTL(new DateInterval('P1Y')); From a857b8eeb26985855c33a1f355b25d53d7080290 Mon Sep 17 00:00:00 2001 From: NikaS Date: Tue, 3 Sep 2024 15:34:24 +0400 Subject: [PATCH 2/4] Fix typo --- src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php index d7ae13f..cfbf98d 100644 --- a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php +++ b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php @@ -90,7 +90,7 @@ public function respondToAccessTokenRequest( } } - // when emulated user requests mew access token. set emulator user id. + // when emulated user requests new access token. set emulator user id. $oldAccessToken = $this->tokenRepository->find($oldRefreshToken['access_token_id']); if ($oldAccessToken->emulator_user_id) { $this->authService->updateAccessToken($accessToken->getIdentifier(), $oldAccessToken->emulator_user_id); From 6f436e277f7aa08ca4eca995f822ec3dcd590fae Mon Sep 17 00:00:00 2001 From: NikaS Date: Wed, 4 Sep 2024 11:31:52 +0400 Subject: [PATCH 3/4] use internal token repository contract, instead of Passport/TokenRepository --- .../Auth/Passport/Grants/InternalRefreshTokenGrant.php | 6 +++--- src/Lodash/Auth/Passport/PassportServiceProvider.php | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php index cfbf98d..aaad2a3 100644 --- a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php +++ b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php @@ -5,7 +5,6 @@ namespace Longman\LaravelLodash\Auth\Passport\Grants; use DateInterval; -use Laravel\Passport\TokenRepository; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; @@ -15,6 +14,7 @@ use League\OAuth2\Server\RequestRefreshTokenEvent; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Longman\LaravelLodash\Auth\Contracts\AuthServiceContract; +use Longman\LaravelLodash\Auth\Contracts\TokenRepositoryContract; use Psr\Http\Message\ServerRequestInterface; use function implode; @@ -23,12 +23,12 @@ class InternalRefreshTokenGrant extends RefreshTokenGrant { - private readonly TokenRepository $tokenRepository; + private readonly TokenRepositoryContract $tokenRepository; private readonly AuthServiceContract $authService; public function __construct( RefreshTokenRepositoryInterface $refreshTokenRepository, - TokenRepository $tokenRepository, + TokenRepositoryContract $tokenRepository, AuthServiceContract $authService, ) { parent::__construct($refreshTokenRepository); diff --git a/src/Lodash/Auth/Passport/PassportServiceProvider.php b/src/Lodash/Auth/Passport/PassportServiceProvider.php index 8250f13..10f5c30 100644 --- a/src/Lodash/Auth/Passport/PassportServiceProvider.php +++ b/src/Lodash/Auth/Passport/PassportServiceProvider.php @@ -9,7 +9,6 @@ use Laravel\Passport\Passport; use Laravel\Passport\PassportServiceProvider as BasePassportServiceProvider; use Laravel\Passport\PassportUserProvider; -use Laravel\Passport\TokenRepository as PassportTokenRepository; use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\ResourceServer; use Longman\LaravelLodash\Auth\Contracts\AuthServiceContract; @@ -107,7 +106,7 @@ protected function makeInternalRefreshTokenGrant(): InternalRefreshTokenGrant { $grant = new InternalRefreshTokenGrant( $this->app->make(RefreshTokenBridgeRepositoryContract::class), - $this->app->make(PassportTokenRepository::class), + $this->app->make(TokenRepositoryContract::class), $this->app->make(AuthServiceContract::class), ); From addff1e5d277300d653d8c2a67b3e6eae749a198 Mon Sep 17 00:00:00 2001 From: NikaS Date: Wed, 4 Sep 2024 14:56:21 +0400 Subject: [PATCH 4/4] Use internal interface --- src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php index aaad2a3..e7d8c94 100644 --- a/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php +++ b/src/Lodash/Auth/Passport/Grants/InternalRefreshTokenGrant.php @@ -8,12 +8,12 @@ use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; -use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\RequestAccessTokenEvent; use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestRefreshTokenEvent; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Longman\LaravelLodash\Auth\Contracts\AuthServiceContract; +use Longman\LaravelLodash\Auth\Contracts\RefreshTokenBridgeRepositoryContract; use Longman\LaravelLodash\Auth\Contracts\TokenRepositoryContract; use Psr\Http\Message\ServerRequestInterface; @@ -27,7 +27,7 @@ class InternalRefreshTokenGrant extends RefreshTokenGrant private readonly AuthServiceContract $authService; public function __construct( - RefreshTokenRepositoryInterface $refreshTokenRepository, + RefreshTokenBridgeRepositoryContract $refreshTokenRepository, TokenRepositoryContract $tokenRepository, AuthServiceContract $authService, ) {