mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-22 13:09:44 +05:30
Adds handling for null
issued refresh token to Grant implementations
This commit is contained in:
parent
b2840474fd
commit
2ea76ca4fd
@ -145,17 +145,17 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue and persist access + refresh tokens
|
// Issue and persist new access token
|
||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
|
||||||
|
|
||||||
// Send events to emitter
|
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
|
||||||
|
|
||||||
// Inject tokens into response type
|
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
|
||||||
|
// Issue and persist new refresh token if given
|
||||||
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
if ($refreshToken !== null) {
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
$responseType->setRefreshToken($refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
// Revoke used auth code
|
// Revoke used auth code
|
||||||
$this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id);
|
$this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id);
|
||||||
|
@ -35,7 +35,10 @@ class PasswordGrant extends AbstractGrant
|
|||||||
RefreshTokenRepositoryInterface $refreshTokenRepository
|
RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||||
) {
|
) {
|
||||||
$this->setUserRepository($userRepository);
|
$this->setUserRepository($userRepository);
|
||||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
|
||||||
|
if ($refreshTokenRepository !== null) {
|
||||||
|
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||||
|
}
|
||||||
|
|
||||||
$this->refreshTokenTTL = new DateInterval('P1M');
|
$this->refreshTokenTTL = new DateInterval('P1M');
|
||||||
}
|
}
|
||||||
@ -56,17 +59,17 @@ class PasswordGrant extends AbstractGrant
|
|||||||
// Finalize the requested scopes
|
// Finalize the requested scopes
|
||||||
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
||||||
|
|
||||||
// Issue and persist new tokens
|
// Issue and persist new access token
|
||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
|
||||||
|
|
||||||
// Send events to emitter
|
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
|
||||||
|
|
||||||
// Inject tokens into response
|
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
|
||||||
|
// Issue and persist new refresh token if given
|
||||||
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
if ($refreshToken !== null) {
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
$responseType->setRefreshToken($refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
return $responseType;
|
return $responseType;
|
||||||
}
|
}
|
||||||
|
@ -63,17 +63,17 @@ class RefreshTokenGrant extends AbstractGrant
|
|||||||
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
||||||
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
|
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
|
||||||
|
|
||||||
// Issue and persist new tokens
|
// Issue and persist new access token
|
||||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
||||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
|
||||||
|
|
||||||
// Send events to emitter
|
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
|
||||||
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
|
||||||
|
|
||||||
// Inject tokens into response
|
|
||||||
$responseType->setAccessToken($accessToken);
|
$responseType->setAccessToken($accessToken);
|
||||||
$responseType->setRefreshToken($refreshToken);
|
|
||||||
|
// Issue and persist new refresh token if given
|
||||||
|
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||||
|
if ($refreshToken !== null) {
|
||||||
|
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
|
||||||
|
$responseType->setRefreshToken($refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
return $responseType;
|
return $responseType;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ use LeagueTests\Stubs\RefreshTokenEntity;
|
|||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
@ -644,6 +645,74 @@ class AuthCodeGrantTest extends TestCase
|
|||||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRespondToAccessTokenRequestNullRefreshToken()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setIdentifier('foo');
|
||||||
|
$client->setRedirectUri('http://foo/bar');
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeEntity = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
/** @var RefreshTokenRepositoryInterface|MockObject $refreshTokenRepositoryMock */
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(null);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(),
|
||||||
|
$refreshTokenRepositoryMock,
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
|
||||||
|
$request = new ServerRequest(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
'POST',
|
||||||
|
'php://input',
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'grant_type' => 'authorization_code',
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
'code' => $this->cryptStub->doEncrypt(
|
||||||
|
json_encode(
|
||||||
|
[
|
||||||
|
'auth_code_id' => uniqid(),
|
||||||
|
'expire_time' => time() + 3600,
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'user_id' => 123,
|
||||||
|
'scopes' => ['foo'],
|
||||||
|
'redirect_uri' => 'http://foo/bar',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var StubResponseType $response */
|
||||||
|
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M'));
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $response->getAccessToken());
|
||||||
|
$this->assertNull($response->getRefreshToken());
|
||||||
|
}
|
||||||
|
|
||||||
public function testRespondToAccessTokenRequestCodeChallengePlain()
|
public function testRespondToAccessTokenRequestCodeChallengePlain()
|
||||||
{
|
{
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
|
@ -16,6 +16,8 @@ use LeagueTests\Stubs\RefreshTokenEntity;
|
|||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
use LeagueTests\Stubs\UserEntity;
|
use LeagueTests\Stubs\UserEntity;
|
||||||
|
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
@ -78,6 +80,56 @@ class PasswordGrantTest extends TestCase
|
|||||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRespondToRequestNullRefreshToken ()
|
||||||
|
{
|
||||||
|
/** @var ClientRepositoryInterface|MockObject $clientRepositoryMock */
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
/** @var AccessTokenRepositoryInterface|MockObject $accessTokenRepositoryMock */
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
/** @var UserRepositoryInterface|MockObject $userRepositoryMock */
|
||||||
|
$userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock();
|
||||||
|
$userEntity = new UserEntity();
|
||||||
|
$userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity);
|
||||||
|
|
||||||
|
/** @var ScopeRepositoryInterface|MockObject $scopeRepositoryMock */
|
||||||
|
$scope = new ScopeEntity();
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope);
|
||||||
|
$scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0);
|
||||||
|
|
||||||
|
/** @var RefreshTokenRepositoryInterface|MockObject $refreshTokenRepositoryMock */
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(null);
|
||||||
|
|
||||||
|
$grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setDefaultScope(self::DEFAULT_SCOPE);
|
||||||
|
|
||||||
|
$serverRequest = new ServerRequest();
|
||||||
|
$serverRequest = $serverRequest->withParsedBody(
|
||||||
|
[
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'client_secret' => 'bar',
|
||||||
|
'username' => 'foo',
|
||||||
|
'password' => 'bar',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$responseType = new StubResponseType();
|
||||||
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
|
$this->assertNull($responseType->getRefreshToken());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@ use LeagueTests\Stubs\CryptTraitStub;
|
|||||||
use LeagueTests\Stubs\RefreshTokenEntity;
|
use LeagueTests\Stubs\RefreshTokenEntity;
|
||||||
use LeagueTests\Stubs\ScopeEntity;
|
use LeagueTests\Stubs\ScopeEntity;
|
||||||
use LeagueTests\Stubs\StubResponseType;
|
use LeagueTests\Stubs\StubResponseType;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
|
|
||||||
@ -94,6 +95,67 @@ class RefreshTokenGrantTest extends TestCase
|
|||||||
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
$this->assertInstanceOf(RefreshTokenEntityInterface::class, $responseType->getRefreshToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRespondToRequestNullRefreshToken()
|
||||||
|
{
|
||||||
|
$client = new ClientEntity();
|
||||||
|
$client->setIdentifier('foo');
|
||||||
|
|
||||||
|
/** @var ClientRepositoryInterface|MockObject $clientRepositoryMock */
|
||||||
|
$clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock();
|
||||||
|
$clientRepositoryMock->method('getClientEntity')->willReturn($client);
|
||||||
|
|
||||||
|
$scopeEntity = new ScopeEntity();
|
||||||
|
$scopeEntity->setIdentifier('foo');
|
||||||
|
|
||||||
|
/** @var ScopeRepositoryInterface|MockObject $scopeRepositoryMock */
|
||||||
|
$scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock();
|
||||||
|
$scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity);
|
||||||
|
|
||||||
|
/** @var AccessTokenRepositoryInterface|MockObject $accessTokenRepositoryMock */
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->expects($this->once())->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
/** @var RefreshTokenRepositoryInterface|MockObject $refreshTokenRepositoryMock */
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(null);
|
||||||
|
$refreshTokenRepositoryMock->expects($this->never())->method('persistNewRefreshToken');
|
||||||
|
|
||||||
|
$grant = new RefreshTokenGrant($refreshTokenRepositoryMock);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setEncryptionKey($this->cryptStub->getKey());
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
|
$oldRefreshToken = $this->cryptStub->doEncrypt(
|
||||||
|
json_encode(
|
||||||
|
[
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'refresh_token_id' => 'zyxwvu',
|
||||||
|
'access_token_id' => 'abcdef',
|
||||||
|
'scopes' => ['foo'],
|
||||||
|
'user_id' => 123,
|
||||||
|
'expire_time' => time() + 3600,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$serverRequest = new ServerRequest();
|
||||||
|
$serverRequest = $serverRequest->withParsedBody([
|
||||||
|
'client_id' => 'foo',
|
||||||
|
'client_secret' => 'bar',
|
||||||
|
'refresh_token' => $oldRefreshToken,
|
||||||
|
'scopes' => ['foo'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$responseType = new StubResponseType();
|
||||||
|
$grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M'));
|
||||||
|
|
||||||
|
$this->assertInstanceOf(AccessTokenEntityInterface::class, $responseType->getAccessToken());
|
||||||
|
$this->assertNull($responseType->getRefreshToken());
|
||||||
|
}
|
||||||
|
|
||||||
public function testRespondToReducedScopes()
|
public function testRespondToReducedScopes()
|
||||||
{
|
{
|
||||||
$client = new ClientEntity();
|
$client = new ClientEntity();
|
||||||
|
Loading…
Reference in New Issue
Block a user