mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-23 05:29:52 +05:30
Added a check for unique access token constraint violation
This commit is contained in:
parent
64a0fcb3a6
commit
b68ef973df
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Ivan Kurnosov <zerkms@zerkms.com>
|
||||||
|
* @copyright Copyright (c) Alex Bilbie
|
||||||
|
* @license http://mit-license.org/
|
||||||
|
*
|
||||||
|
* @link https://github.com/thephpleague/oauth2-server
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace League\OAuth2\Server\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class UniqueTokenIdentifierConstraintViolationException extends OAuthServerException
|
||||||
|
{
|
||||||
|
public static function create()
|
||||||
|
{
|
||||||
|
$errorMessage = 'Could not create unique access token identifier';
|
||||||
|
|
||||||
|
return new static($errorMessage, 100, 'access_token_duplicate', 500);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
|||||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||||
@ -35,6 +36,8 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
|
|
||||||
const SCOPE_DELIMITER_STRING = ' ';
|
const SCOPE_DELIMITER_STRING = ' ';
|
||||||
|
|
||||||
|
const MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ClientRepositoryInterface
|
* @var ClientRepositoryInterface
|
||||||
*/
|
*/
|
||||||
@ -295,19 +298,28 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$userIdentifier,
|
$userIdentifier,
|
||||||
array $scopes = []
|
array $scopes = []
|
||||||
) {
|
) {
|
||||||
|
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||||
|
|
||||||
$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
|
$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
|
||||||
$accessToken->setClient($client);
|
$accessToken->setClient($client);
|
||||||
$accessToken->setUserIdentifier($userIdentifier);
|
$accessToken->setUserIdentifier($userIdentifier);
|
||||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
|
||||||
$accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL));
|
$accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL));
|
||||||
|
|
||||||
foreach ($scopes as $scope) {
|
foreach ($scopes as $scope) {
|
||||||
$accessToken->addScope($scope);
|
$accessToken->addScope($scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while ($maxGenerationAttempts-- > 0) {
|
||||||
|
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||||
|
try {
|
||||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||||
|
|
||||||
return $accessToken;
|
return $accessToken;
|
||||||
|
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||||
|
if ($maxGenerationAttempts === 0) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,8 +340,9 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$redirectUri,
|
$redirectUri,
|
||||||
array $scopes = []
|
array $scopes = []
|
||||||
) {
|
) {
|
||||||
|
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||||
|
|
||||||
$authCode = $this->authCodeRepository->getNewAuthCode();
|
$authCode = $this->authCodeRepository->getNewAuthCode();
|
||||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
|
||||||
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
||||||
$authCode->setClient($client);
|
$authCode->setClient($client);
|
||||||
$authCode->setUserIdentifier($userIdentifier);
|
$authCode->setUserIdentifier($userIdentifier);
|
||||||
@ -339,9 +352,17 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
$authCode->addScope($scope);
|
$authCode->addScope($scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while ($maxGenerationAttempts-- > 0) {
|
||||||
|
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||||
|
try {
|
||||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||||
|
|
||||||
return $authCode;
|
return $authCode;
|
||||||
|
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||||
|
if ($maxGenerationAttempts === 0) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -351,14 +372,23 @@ abstract class AbstractGrant implements GrantTypeInterface
|
|||||||
*/
|
*/
|
||||||
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
|
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
|
||||||
{
|
{
|
||||||
|
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
|
||||||
|
|
||||||
$refreshToken = $this->refreshTokenRepository->getNewRefreshToken();
|
$refreshToken = $this->refreshTokenRepository->getNewRefreshToken();
|
||||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
|
||||||
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
||||||
$refreshToken->setAccessToken($accessToken);
|
$refreshToken->setAccessToken($accessToken);
|
||||||
|
|
||||||
|
while ($maxGenerationAttempts-- > 0) {
|
||||||
|
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||||
|
try {
|
||||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||||
|
|
||||||
return $refreshToken;
|
return $refreshToken;
|
||||||
|
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
|
||||||
|
if ($maxGenerationAttempts === 0) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ use League\OAuth2\Server\CryptKey;
|
|||||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||||
@ -1183,4 +1184,299 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals($e->getHint(), 'Check the `code_verifier` parameter');
|
$this->assertEquals($e->getHint(), 'Check the `code_verifier` parameter');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAuthCodeRepositoryUniqueConstraintCheck()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||||
|
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||||
|
|
||||||
|
$authCodeRepository->expects($this->at(0))->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
$authCodeRepository->expects($this->at(1))->method('persistNewAuthCode');
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$authCodeRepository,
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
|
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
* @expectedExceptionCode 7
|
||||||
|
*/
|
||||||
|
public function testAuthCodeRepositoryFailToPersist()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||||
|
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||||
|
$authCodeRepository->method('persistNewAuthCode')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$authCodeRepository,
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
|
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||||
|
* @expectedExceptionCode 100
|
||||||
|
*/
|
||||||
|
public function testAuthCodeRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
$authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock();
|
||||||
|
$authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity());
|
||||||
|
$authCodeRepository->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$authCodeRepository,
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
|
||||||
|
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRefreshTokenRepositoryUniqueConstraintCheck()
|
||||||
|
{
|
||||||
|
$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();
|
||||||
|
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
$refreshTokenRepositoryMock->expects($this->at(0))->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
$refreshTokenRepositoryMock->expects($this->at(1))->method('persistNewRefreshToken');
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
|
$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->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||||
|
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
* @expectedExceptionCode 7
|
||||||
|
*/
|
||||||
|
public function testRefreshTokenRepositoryFailToPersist()
|
||||||
|
{
|
||||||
|
$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();
|
||||||
|
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
|
$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->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||||
|
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||||
|
* @expectedExceptionCode 100
|
||||||
|
*/
|
||||||
|
public function testRefreshTokenRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||||
|
{
|
||||||
|
$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();
|
||||||
|
|
||||||
|
$refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock();
|
||||||
|
$refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity());
|
||||||
|
$refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$this->getMock(AuthCodeRepositoryInterface::class),
|
||||||
|
$this->getMock(RefreshTokenRepositoryInterface::class),
|
||||||
|
new \DateInterval('PT10M')
|
||||||
|
);
|
||||||
|
$grant->setClientRepository($clientRepositoryMock);
|
||||||
|
$grant->setScopeRepository($scopeRepositoryMock);
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
$grant->setRefreshTokenRepository($refreshTokenRepositoryMock);
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
|
||||||
|
$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->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface);
|
||||||
|
$this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface);
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,6 +3,8 @@
|
|||||||
namespace LeagueTests\Grant;
|
namespace LeagueTests\Grant;
|
||||||
|
|
||||||
use League\OAuth2\Server\CryptKey;
|
use League\OAuth2\Server\CryptKey;
|
||||||
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
use League\OAuth2\Server\Grant\ImplicitGrant;
|
use League\OAuth2\Server\Grant\ImplicitGrant;
|
||||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||||
@ -295,4 +297,76 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$grant->completeAuthorizationRequest($authRequest);
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAccessTokenRepositoryUniqueConstraintCheck()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->expects($this->at(0))->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
$accessTokenRepositoryMock->expects($this->at(1))->method('persistNewAccessToken')->willReturnSelf();
|
||||||
|
|
||||||
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
|
$this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
* @expectedExceptionCode 7
|
||||||
|
*/
|
||||||
|
public function testAccessTokenRepositoryFailToPersist()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(OAuthServerException::serverError('something bad happened'));
|
||||||
|
|
||||||
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
|
||||||
|
* @expectedExceptionCode 100
|
||||||
|
*/
|
||||||
|
public function testAccessTokenRepositoryFailToPersistUniqueNoInfiniteLoop()
|
||||||
|
{
|
||||||
|
$authRequest = new AuthorizationRequest();
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
$authRequest->setClient(new ClientEntity());
|
||||||
|
$authRequest->setGrantTypeId('authorization_code');
|
||||||
|
$authRequest->setUser(new UserEntity());
|
||||||
|
|
||||||
|
/** @var AccessTokenRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject $accessTokenRepositoryMock */
|
||||||
|
$accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock();
|
||||||
|
$accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity());
|
||||||
|
$accessTokenRepositoryMock->method('persistNewAccessToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create());
|
||||||
|
|
||||||
|
$grant = new ImplicitGrant(new \DateInterval('PT10M'));
|
||||||
|
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
|
||||||
|
$grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key'));
|
||||||
|
$grant->setAccessTokenRepository($accessTokenRepositoryMock);
|
||||||
|
|
||||||
|
$grant->completeAuthorizationRequest($authRequest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user