mirror of
				https://github.com/elyby/oauth2-server.git
				synced 2025-05-31 14:12:07 +05:30 
			
		
		
		
	Merge branch 'feature/refresh-token-rotation' into develop
This commit is contained in:
		| @@ -54,6 +54,12 @@ class RefreshToken implements GrantTypeInterface { | ||||
|      */ | ||||
|     protected $refreshTokenTTL = 604800; | ||||
|  | ||||
|     /** | ||||
|      * Rotate refresh tokens | ||||
|      * @var boolean | ||||
|      */ | ||||
|     protected $rotateRefreshTokens = false; | ||||
|  | ||||
|     /** | ||||
|      * Constructor | ||||
|      * @param Authorization $authServer Authorization server instance | ||||
| @@ -111,6 +117,16 @@ class RefreshToken implements GrantTypeInterface { | ||||
|         return $this->refreshTokenTTL; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * When a new access is token, expire the refresh token used and issue a new one. | ||||
|      * @param  boolean $rotateRefreshTokens Set to true to enable (default = false) | ||||
|      * @return void | ||||
|      */ | ||||
|     public function rotateRefreshTokens($rotateRefreshTokens = false) | ||||
|     { | ||||
|         $this->rotateRefreshTokens = $rotateRefreshTokens; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Complete the refresh token grant | ||||
|      * @param  null|array $inputParams | ||||
| @@ -160,24 +176,32 @@ class RefreshToken implements GrantTypeInterface { | ||||
|         $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL(); | ||||
|         $accessTokenExpires = time() + $accessTokenExpiresIn; | ||||
|  | ||||
|         // Generate a new refresh token | ||||
|         $refreshToken = SecureKey::make(); | ||||
|         $refreshTokenExpires = time() + $this->getRefreshTokenTTL(); | ||||
|  | ||||
|         // Revoke the old refresh token | ||||
|         $this->authServer->getStorage('session')->removeRefreshToken($authParams['refresh_token']); | ||||
|  | ||||
|         // Associate the new access token with the session | ||||
|         $newAccessTokenId = $this->authServer->getStorage('session')->associateAccessToken($accessTokenDetails['session_id'], $accessToken, $accessTokenExpires); | ||||
|  | ||||
|         // There isn't a request for reduced scopes so assign the original ones | ||||
|         if ($this->rotateRefreshTokens === true) { | ||||
|  | ||||
|             // Generate a new refresh token | ||||
|             $refreshToken = SecureKey::make(); | ||||
|             $refreshTokenExpires = time() + $this->getRefreshTokenTTL(); | ||||
|  | ||||
|             // Revoke the old refresh token | ||||
|             $this->authServer->getStorage('session')->removeRefreshToken($authParams['refresh_token']); | ||||
|  | ||||
|             // Associate the new refresh token with the new access token | ||||
|             $this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']); | ||||
|         } | ||||
|  | ||||
|         // There isn't a request for reduced scopes so assign the original ones (or we're not rotating scopes) | ||||
|         if ( ! isset($authParams['scope'])) { | ||||
|  | ||||
|             foreach ($scopes as $scope) { | ||||
|                 $this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']); | ||||
|             } | ||||
|         } else { | ||||
|  | ||||
|             // The request is asking for reduced scopes | ||||
|         } elseif ( isset($authParams['scope']) && $this->rotateRefreshTokens === true) { | ||||
|  | ||||
|             // The request is asking for reduced scopes and rotate tokens is enabled | ||||
|             $reqestedScopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']); | ||||
|  | ||||
|             for ($i = 0; $i < count($reqestedScopes); $i++) { | ||||
| @@ -202,16 +226,18 @@ class RefreshToken implements GrantTypeInterface { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Associate the new refresh token with the new access token | ||||
|         $this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']); | ||||
|  | ||||
|         return array( | ||||
|         $response = array( | ||||
|             'access_token'  =>  $accessToken, | ||||
|             'refresh_token' =>  $refreshToken, | ||||
|             'token_type'    =>  'bearer', | ||||
|             'expires'       =>  $accessTokenExpires, | ||||
|             'expires_in'    =>  $accessTokenExpiresIn | ||||
|         ); | ||||
|  | ||||
|         if ($this->rotateRefreshTokens === true) { | ||||
|             $response['refresh_token'] = $refreshToken; | ||||
|         } | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -204,7 +204,6 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase | ||||
|         $this->assertArrayHasKey('token_type', $v); | ||||
|         $this->assertArrayHasKey('expires', $v); | ||||
|         $this->assertArrayHasKey('expires_in', $v); | ||||
|         $this->assertArrayHasKey('refresh_token', $v); | ||||
|  | ||||
|         $this->assertEquals($a->getAccessTokenTTL(), $v['expires_in']); | ||||
|         $this->assertEquals(time()+$a->getAccessTokenTTL(), $v['expires']); | ||||
| @@ -240,6 +239,48 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase | ||||
|             'refresh_token'  =>  'abcdef', | ||||
|         )); | ||||
|  | ||||
|         $this->assertArrayHasKey('access_token', $v); | ||||
|         $this->assertArrayHasKey('token_type', $v); | ||||
|         $this->assertArrayHasKey('expires', $v); | ||||
|         $this->assertArrayHasKey('expires_in', $v); | ||||
|  | ||||
|         $this->assertEquals($a->getAccessTokenTTL(), $v['expires_in']); | ||||
|         $this->assertEquals(time()+$a->getAccessTokenTTL(), $v['expires']); | ||||
|     } | ||||
|  | ||||
|     public function test_issueAccessToken_refreshTokenGrant_rotateTokens() | ||||
|     { | ||||
|         $this->client->shouldReceive('getClient')->andReturn(array( | ||||
|             'client_id' =>  1234, | ||||
|             'client_secret' =>  5678, | ||||
|             'redirect_uri'  =>  'http://foo/redirect', | ||||
|             'name'  =>  'Example Client' | ||||
|         )); | ||||
|  | ||||
|         $this->session->shouldReceive('validateRefreshToken')->andReturn(1); | ||||
|         $this->session->shouldReceive('validateAuthCode')->andReturn(1); | ||||
|         $this->session->shouldReceive('updateSession')->andReturn(null); | ||||
|         $this->session->shouldReceive('updateRefreshToken')->andReturn(null); | ||||
|         $this->session->shouldReceive('getAccessToken')->andReturn(null); | ||||
|         $this->session->shouldReceive('getScopes')->andReturn(array('id'    =>  1)); | ||||
|         $this->session->shouldReceive('associateAccessToken')->andReturn(1); | ||||
|         $this->session->shouldReceive('associateRefreshToken')->andReturn(1); | ||||
|         $this->session->shouldReceive('removeRefreshToken')->andReturn(1); | ||||
|         $this->session->shouldReceive('associateScope')->andReturn(null); | ||||
|  | ||||
|         $a = $this->returnDefault(); | ||||
|  | ||||
|         $rt = new League\OAuth2\Server\Grant\RefreshToken($a); | ||||
|         $rt->rotateRefreshTokens(true); | ||||
|         $a->addGrantType($rt); | ||||
|  | ||||
|         $v = $a->issueAccessToken(array( | ||||
|             'grant_type'    =>  'refresh_token', | ||||
|             'client_id' =>  1234, | ||||
|             'client_secret' =>  5678, | ||||
|             'refresh_token'  =>  'abcdef', | ||||
|         )); | ||||
|  | ||||
|         $this->assertArrayHasKey('access_token', $v); | ||||
|         $this->assertArrayHasKey('token_type', $v); | ||||
|         $this->assertArrayHasKey('expires', $v); | ||||
| @@ -286,7 +327,6 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase | ||||
|         $this->assertArrayHasKey('token_type', $v); | ||||
|         $this->assertArrayHasKey('expires', $v); | ||||
|         $this->assertArrayHasKey('expires_in', $v); | ||||
|         $this->assertArrayHasKey('refresh_token', $v); | ||||
|  | ||||
|         $this->assertNotEquals($a->getAccessTokenTTL(), $v['expires_in']); | ||||
|         $this->assertNotEquals(time()+$a->getAccessTokenTTL(), $v['expires']); | ||||
| @@ -318,6 +358,7 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase | ||||
|         $a = $this->returnDefault(); | ||||
|         $grant = new League\OAuth2\Server\Grant\RefreshToken($a); | ||||
|         $grant->setAccessTokenTTL(30); | ||||
|         $grant->rotateRefreshTokens(true); | ||||
|         $a->addGrantType($grant); | ||||
|  | ||||
|         $v = $a->issueAccessToken(array( | ||||
| @@ -368,6 +409,7 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase | ||||
|         $a = $this->returnDefault(); | ||||
|         $grant = new League\OAuth2\Server\Grant\RefreshToken($a); | ||||
|         $grant->setAccessTokenTTL(30); | ||||
|         $grant->rotateRefreshTokens(true); | ||||
|         $a->addGrantType($grant); | ||||
|  | ||||
|         $a->issueAccessToken(array( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user