From 981c4da5d3bcfa305680b5b98a10083b6f9ace4c Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 1 Oct 2024 12:41:28 +0330 Subject: [PATCH 1/3] issue and persist a new refresh token --- src/Grant/RefreshTokenGrant.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index a632990c7..ad7c32326 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -83,13 +83,11 @@ public function respondToAccessTokenRequest( $responseType->setAccessToken($accessToken); // Issue and persist new refresh token if given - if ($this->revokeRefreshTokens) { - $refreshToken = $this->issueRefreshToken($accessToken); + $refreshToken = $this->issueRefreshToken($accessToken); - if ($refreshToken !== null) { - $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken)); - $responseType->setRefreshToken($refreshToken); - } + if ($refreshToken !== null) { + $this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken)); + $responseType->setRefreshToken($refreshToken); } return $responseType; From 921713744e2f84a424d7b151155d37cc9216898c Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 11 Oct 2024 04:09:49 +0330 Subject: [PATCH 2/3] add tests --- tests/Grant/RefreshTokenGrantTest.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index b37001a80..fbebcac6d 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -5,6 +5,7 @@ namespace LeagueTests\Grant; use DateInterval; +use Laminas\Diactoros\Response; use Laminas\Diactoros\ServerRequest; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; @@ -14,6 +15,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; @@ -688,11 +690,15 @@ public function testUnrevokedRefreshToken(): void $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); $scopeRepositoryMock->method('finalizeScopes')->willReturn([$scopeEntity]); + $accessTokenEntity = new AccessTokenEntity(); + $accessTokenEntity->setClient($client); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $accessTokenRepositoryMock->method('getNewToken')->willReturn($accessTokenEntity); $accessTokenRepositoryMock->expects(self::once())->method('persistNewAccessToken')->willReturnSelf(); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $refreshTokenRepositoryMock->method('isRefreshTokenRevoked')->willReturn(false); $refreshTokenRepositoryMock->expects(self::never())->method('revokeRefreshToken'); @@ -727,11 +733,22 @@ public function testUnrevokedRefreshToken(): void $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setPrivateKey($privateKey = new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $grant->revokeRefreshTokens(false); - $grant->respondToAccessTokenRequest($serverRequest, new StubResponseType(), new DateInterval('PT5M')); + $responseType = new BearerTokenResponse(); + $responseType->setPrivateKey($privateKey); + $responseType->setEncryptionKey($this->cryptStub->getKey()); + + $response = $grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M')) + ->generateHttpResponse(new Response()); + + $json = json_decode((string) $response->getBody()); self::assertFalse($refreshTokenRepositoryMock->isRefreshTokenRevoked($refreshTokenId)); + self::assertEquals('Bearer', $json->token_type); + self::assertObjectHasProperty('expires_in', $json); + self::assertObjectHasProperty('access_token', $json); + self::assertObjectHasProperty('refresh_token', $json); } } From 844d86dc9b5fb8e2929d63c6c99861aa29806b6b Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 11 Oct 2024 15:47:34 +0330 Subject: [PATCH 3/3] add changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c99ac6c..6aa241cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Auto-generated event emitter is now persisted. Previously, a new emitter was generated every time (PR #1428) - Fixed bug where you could not omit a redirect uri even if one had not been specified during the auth request (PR #1428) +- Fixed bug where disabling refresh token revocation via `revokeRefreshTokens(false)` unintentionally disables issuing new refresh token (PR #1449) ## [9.0.0] - released 2024-05-13 ### Added - Device Authorization Grant added (PR #1074) -- GrantTypeInterface has a new function, `revokeRefreshTokens()` for enabling or disabling refresh tokens after use (PR #1375) +- GrantTypeInterface has a new function, `revokeRefreshTokens()` for enabling or disabling refresh token revocation (PR #1375) - A CryptKeyInterface to allow developers to change the CryptKey implementation with greater ease (PR #1044) - The authorization server can now finalize scopes when a client uses a refresh token (PR #1094) - An AuthorizationRequestInterface to make it easier to extend the AuthorizationRequest (PR #1110)