diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index bde97d6eb..acfada2c5 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -15,6 +15,8 @@ use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGenerator; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -79,15 +81,21 @@ class AuthorizationServer implements EmitterAwareInterface */ private $defaultScope = ''; + /** + * @var IdentifierGeneratorInterface + */ + private $identifierGenerator; + /** * New server instance. * - * @param ClientRepositoryInterface $clientRepository - * @param AccessTokenRepositoryInterface $accessTokenRepository - * @param ScopeRepositoryInterface $scopeRepository - * @param CryptKey|string $privateKey - * @param string|Key $encryptionKey - * @param null|ResponseTypeInterface $responseType + * @param ClientRepositoryInterface $clientRepository + * @param AccessTokenRepositoryInterface $accessTokenRepository + * @param ScopeRepositoryInterface $scopeRepository + * @param CryptKey|string $privateKey + * @param string|Key $encryptionKey + * @param null|ResponseTypeInterface $responseType + * @param null|IdentifierGeneratorInterface $identifierGenerator */ public function __construct( ClientRepositoryInterface $clientRepository, @@ -95,7 +103,8 @@ public function __construct( ScopeRepositoryInterface $scopeRepository, $privateKey, $encryptionKey, - ResponseTypeInterface $responseType = null + ResponseTypeInterface $responseType = null, + IdentifierGeneratorInterface $identifierGenerator = null ) { $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; @@ -115,6 +124,12 @@ public function __construct( } $this->responseType = $responseType; + + if ($identifierGenerator === null) { + $identifierGenerator = new IdentifierGenerator(); + } + + $this->identifierGenerator = $identifierGenerator; } /** @@ -136,6 +151,7 @@ public function enableGrantType(GrantTypeInterface $grantType, DateInterval $acc $grantType->setPrivateKey($this->privateKey); $grantType->setEmitter($this->getEmitter()); $grantType->setEncryptionKey($this->encryptionKey); + $grantType->setIdentifierGenerator($this->identifierGenerator); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 492133317..fc7f86c71 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,8 +12,6 @@ use DateInterval; use DateTime; -use Error; -use Exception; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; @@ -24,6 +22,7 @@ use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -34,7 +33,6 @@ use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use LogicException; use Psr\Http\Message\ServerRequestInterface; -use TypeError; /** * Abstract grant class. @@ -92,6 +90,11 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $defaultScope; + /** + * @var IdentifierGeneratorInterface + */ + protected $identifierGenerator; + /** * @param ClientRepositoryInterface $clientRepository */ @@ -166,6 +169,14 @@ public function setDefaultScope($scope) $this->defaultScope = $scope; } + /** + * @param IdentifierGeneratorInterface $identifierGenerator + */ + public function setIdentifierGenerator(IdentifierGeneratorInterface $identifierGenerator) + { + $this->identifierGenerator = $identifierGenerator; + } + /** * Validate the client. * @@ -403,7 +414,7 @@ protected function issueAccessToken( } while ($maxGenerationAttempts-- > 0) { - $accessToken->setIdentifier($this->generateUniqueIdentifier()); + $accessToken->setIdentifier($this->identifierGenerator->generateUniqueIdentifier()); try { $this->accessTokenRepository->persistNewAccessToken($accessToken); @@ -453,7 +464,7 @@ protected function issueAuthCode( } while ($maxGenerationAttempts-- > 0) { - $authCode->setIdentifier($this->generateUniqueIdentifier()); + $authCode->setIdentifier($this->identifierGenerator->generateUniqueIdentifier()); try { $this->authCodeRepository->persistNewAuthCode($authCode); @@ -483,7 +494,7 @@ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken) $refreshToken->setAccessToken($accessToken); while ($maxGenerationAttempts-- > 0) { - $refreshToken->setIdentifier($this->generateUniqueIdentifier()); + $refreshToken->setIdentifier($this->identifierGenerator->generateUniqueIdentifier()); try { $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); @@ -496,31 +507,6 @@ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken) } } - /** - * Generate a new unique identifier. - * - * @param int $length - * - * @throws OAuthServerException - * - * @return string - */ - protected function generateUniqueIdentifier($length = 40) - { - try { - return bin2hex(random_bytes($length)); - // @codeCoverageIgnoreStart - } catch (TypeError $e) { - throw OAuthServerException::serverError('An unexpected error has occurred', $e); - } catch (Error $e) { - throw OAuthServerException::serverError('An unexpected error has occurred', $e); - } catch (Exception $e) { - // If you get this message, the CSPRNG failed hard. - throw OAuthServerException::serverError('Could not generate a random string', $e); - } - // @codeCoverageIgnoreEnd - } - /** * {@inheritdoc} */ diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 41ebeb5ff..917c55f23 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -15,6 +15,7 @@ use Defuse\Crypto\Key; use League\Event\EmitterAwareInterface; use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -141,4 +142,11 @@ public function setPrivateKey(CryptKey $privateKey); * @param string|Key|null $key */ public function setEncryptionKey($key = null); + + /** + * Set the identifier generator + * + * @param IdentifierGeneratorInterface $identifierGenerator + */ + public function setIdentifierGenerator(IdentifierGeneratorInterface $identifierGenerator); } diff --git a/src/IdentifierGenerator/IdentifierGenerator.php b/src/IdentifierGenerator/IdentifierGenerator.php new file mode 100644 index 000000000..911bdf449 --- /dev/null +++ b/src/IdentifierGenerator/IdentifierGenerator.php @@ -0,0 +1,30 @@ +method('getNewRefreshToken') ->willReturn(new RefreshTokenEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setRefreshTokenTTL(new \DateInterval('PT1M')); $grantMock->setRefreshTokenRepository($refreshTokenRepoMock); + $grantMock->setIdentifierGenerator($identifierGeneratorMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueRefreshTokenMethod = $abstractGrantReflection->getMethod('issueRefreshToken'); @@ -351,9 +356,13 @@ public function testIssueAccessToken() $accessTokenRepoMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepoMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setAccessTokenRepository($accessTokenRepoMock); + $grantMock->setIdentifierGenerator($identifierGeneratorMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueAccessTokenMethod = $abstractGrantReflection->getMethod('issueAccessToken'); @@ -375,9 +384,13 @@ public function testIssueAuthCode() $authCodeRepoMock = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setAuthCodeRepository($authCodeRepoMock); + $grantMock->setIdentifierGenerator($identifierGeneratorMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode'); @@ -460,17 +473,6 @@ public function testValidateScopesBadScope() $grantMock->validateScopes('basic '); } - public function testGenerateUniqueIdentifier() - { - $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); - - $abstractGrantReflection = new \ReflectionClass($grantMock); - $method = $abstractGrantReflection->getMethod('generateUniqueIdentifier'); - $method->setAccessible(true); - - $this->assertInternalType('string', $method->invoke($grantMock)); - } - public function testCanRespondToAuthorizationRequest() { $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 6a3192343..7441cbec9 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -7,6 +7,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use League\OAuth2\Server\Grant\AuthCodeGrant; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -542,12 +543,16 @@ public function testCompleteAuthorizationRequest() $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $authCodeRepository, $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -598,6 +603,9 @@ public function testRespondToAccessTokenRequest() $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -608,6 +616,7 @@ public function testRespondToAccessTokenRequest() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], @@ -665,6 +674,9 @@ public function testRespondToAccessTokenRequestCodeChallengePlain() $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -676,6 +688,7 @@ public function testRespondToAccessTokenRequestCodeChallengePlain() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], @@ -736,6 +749,9 @@ public function testRespondToAccessTokenRequestCodeChallengeS256() $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -747,6 +763,7 @@ public function testRespondToAccessTokenRequestCodeChallengeS256() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], @@ -1531,12 +1548,16 @@ public function testAuthCodeRepositoryUniqueConstraintCheck() $authCodeRepository->expects($this->at(0))->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create()); $authCodeRepository->expects($this->at(1))->method('persistNewAuthCode'); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $authCodeRepository, $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -1557,12 +1578,16 @@ public function testAuthCodeRepositoryFailToPersist() $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); $authCodeRepository->method('persistNewAuthCode')->willThrowException(OAuthServerException::serverError('something bad happened')); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $authCodeRepository, $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -1583,11 +1608,15 @@ public function testAuthCodeRepositoryFailToPersistUniqueNoInfiniteLoop() $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); $authCodeRepository->method('persistNewAuthCode')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $authCodeRepository, $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -1614,6 +1643,9 @@ public function testRefreshTokenRepositoryUniqueConstraintCheck() $refreshTokenRepositoryMock->expects($this->at(0))->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create()); $refreshTokenRepositoryMock->expects($this->at(1))->method('persistNewRefreshToken'); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -1624,6 +1656,7 @@ public function testRefreshTokenRepositoryUniqueConstraintCheck() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], @@ -1685,6 +1718,9 @@ public function testRefreshTokenRepositoryFailToPersist() $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(OAuthServerException::serverError('something bad happened')); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -1695,6 +1731,7 @@ public function testRefreshTokenRepositoryFailToPersist() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], @@ -1756,6 +1793,9 @@ public function testRefreshTokenRepositoryFailToPersistUniqueNoInfiniteLoop() $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willThrowException(UniqueTokenIdentifierConstraintViolationException::create()); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), @@ -1766,6 +1806,7 @@ public function testRefreshTokenRepositoryFailToPersistUniqueNoInfiniteLoop() $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); + $grant->setIdentifierGenerator($identifierGeneratorMock); $request = new ServerRequest( [], diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 6c7b5a363..ea2933017 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -4,6 +4,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -39,11 +40,15 @@ public function testRespondToRequest() $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new ClientCredentialsGrant(); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setDefaultScope(self::DEFAULT_SCOPE); + $grant->setIdentifierGenerator($identifierGeneratorMock); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 257ea16d7..aa61b5dd5 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use League\OAuth2\Server\Grant\ImplicitGrant; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; @@ -288,10 +289,14 @@ public function testCompleteAuthorizationRequest() $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->expects($this->once())->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -342,10 +347,14 @@ public function testAccessTokenRepositoryUniqueConstraintCheck() $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); + $grant->setIdentifierGenerator($identifierGeneratorMock); $this->assertInstanceOf(RedirectResponse::class, $grant->completeAuthorizationRequest($authRequest)); } @@ -371,10 +380,14 @@ public function testAccessTokenRepositoryFailToPersist() $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); + $grant->setIdentifierGenerator($identifierGeneratorMock); $grant->completeAuthorizationRequest($authRequest); } @@ -400,10 +413,14 @@ public function testAccessTokenRepositoryFailToPersistUniqueNoInfiniteLoop() $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); + $grant->setIdentifierGenerator($identifierGeneratorMock); $grant->completeAuthorizationRequest($authRequest); } diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 2ee700f88..441be6d99 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -5,6 +5,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Grant\PasswordGrant; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; @@ -55,11 +56,15 @@ public function testRespondToRequest() $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setDefaultScope(self::DEFAULT_SCOPE); + $grant->setIdentifierGenerator($identifierGeneratorMock); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 895981155..ef5945292 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Grant\RefreshTokenGrant; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; @@ -59,12 +60,16 @@ public function testRespondToRequest() $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $refreshTokenRepositoryMock->expects($this->once())->method('persistNewRefreshToken')->willReturnSelf(); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $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')); + $grant->setIdentifierGenerator($identifierGeneratorMock); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -114,12 +119,16 @@ public function testRespondToReducedScopes() $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + $identifierGeneratorMock = $this->getMockBuilder(IdentifierGeneratorInterface::class)->getMock(); + $identifierGeneratorMock->method('generateUniqueIdentifier')->willReturn(uniqid()); + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setIdentifierGenerator($identifierGeneratorMock); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode(