From 9fe937170dd464e3b6f514d0bb02f1125b7cbf5a Mon Sep 17 00:00:00 2001 From: Patrick Rodacker Date: Sat, 19 Jan 2019 22:25:47 +0100 Subject: [PATCH 1/5] decouple unique identifier generator --- src/AuthorizationServer.php | 30 +++++++++--- src/Grant/AbstractGrant.php | 46 ++++++------------- .../IdentifierGenerator.php | 31 +++++++++++++ .../IdentifierGeneratorInterface.php | 15 ++++++ tests/Grant/AbstractGrantTest.php | 16 ++----- tests/Grant/AuthCodeGrantTest.php | 41 +++++++++++++++++ tests/Grant/ClientCredentialsGrantTest.php | 5 ++ tests/Grant/ImplicitGrantTest.php | 17 +++++++ tests/Grant/PasswordGrantTest.php | 5 ++ tests/Grant/RefreshTokenGrantTest.php | 9 ++++ 10 files changed, 166 insertions(+), 49 deletions(-) create mode 100644 src/IdentifierGenerator/IdentifierGenerator.php create mode 100644 src/IdentifierGenerator/IdentifierGeneratorInterface.php diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index bde97d6eb..de353c03e 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -13,6 +13,8 @@ use Defuse\Crypto\Key; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGenerator; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -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..ddcaa1ae5 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,14 +12,14 @@ use DateInterval; use DateTime; -use Error; -use Exception; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGenerator; +use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -34,7 +34,6 @@ use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use LogicException; use Psr\Http\Message\ServerRequestInterface; -use TypeError; /** * Abstract grant class. @@ -92,6 +91,11 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $defaultScope; + /** + * @var IdentifierGeneratorInterface + */ + protected $identifierGenerator; + /** * @param ClientRepositoryInterface $clientRepository */ @@ -166,6 +170,11 @@ public function setDefaultScope($scope) $this->defaultScope = $scope; } + public function setIdentifierGenerator(IdentifierGeneratorInterface $identifierGenerator) + { + $this->identifierGenerator = $identifierGenerator; + } + /** * Validate the client. * @@ -403,7 +412,7 @@ protected function issueAccessToken( } while ($maxGenerationAttempts-- > 0) { - $accessToken->setIdentifier($this->generateUniqueIdentifier()); + $accessToken->setIdentifier($this->identifierGenerator->generateUniqueIdentifier()); try { $this->accessTokenRepository->persistNewAccessToken($accessToken); @@ -453,7 +462,7 @@ protected function issueAuthCode( } while ($maxGenerationAttempts-- > 0) { - $authCode->setIdentifier($this->generateUniqueIdentifier()); + $authCode->setIdentifier($this->identifierGenerator->generateUniqueIdentifier()); try { $this->authCodeRepository->persistNewAuthCode($authCode); @@ -483,7 +492,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 +505,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/IdentifierGenerator/IdentifierGenerator.php b/src/IdentifierGenerator/IdentifierGenerator.php new file mode 100644 index 000000000..70f60dc5d --- /dev/null +++ b/src/IdentifierGenerator/IdentifierGenerator.php @@ -0,0 +1,31 @@ +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 +465,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( From 6bc8d6d8de0c3b91f4092a04e0d3ab2ba633965a Mon Sep 17 00:00:00 2001 From: Patrick Rodacker Date: Sat, 19 Jan 2019 23:21:47 +0100 Subject: [PATCH 2/5] applied cs diff --- src/AuthorizationServer.php | 18 +++++++++--------- src/Grant/AbstractGrant.php | 3 +-- .../IdentifierGenerator.php | 3 +-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index de353c03e..acfada2c5 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -13,10 +13,10 @@ use Defuse\Crypto\Key; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; -use League\OAuth2\Server\IdentifierGenerator\IdentifierGenerator; -use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; 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; @@ -89,13 +89,13 @@ class AuthorizationServer implements EmitterAwareInterface /** * 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 null|IdentifierGeneratorInterface $identifierGenerator + * @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, diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ddcaa1ae5..b3b66432b 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -18,12 +18,11 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; -use League\OAuth2\Server\IdentifierGenerator\IdentifierGenerator; -use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; 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; diff --git a/src/IdentifierGenerator/IdentifierGenerator.php b/src/IdentifierGenerator/IdentifierGenerator.php index 70f60dc5d..911bdf449 100644 --- a/src/IdentifierGenerator/IdentifierGenerator.php +++ b/src/IdentifierGenerator/IdentifierGenerator.php @@ -5,13 +5,12 @@ use Error; use Exception; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\IdentifierGenerator\IdentifierGeneratorInterface; use TypeError; class IdentifierGenerator implements IdentifierGeneratorInterface { /** - * @inheritdoc + * {@inheritdoc} */ public function generateUniqueIdentifier($length = 40) { From 187769d06a7a560abf7b73d97ccd8ecaf86f3fb8 Mon Sep 17 00:00:00 2001 From: Patrick Rodacker Date: Sat, 19 Jan 2019 23:26:20 +0100 Subject: [PATCH 3/5] fixes test --- tests/Grant/AbstractGrantTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index e721f7c15..391d1883b 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -331,10 +331,14 @@ public function testIssueRefreshToken() ->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'); @@ -352,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'); From 49a0b7b76741acfc0f7a688407b7c8d76d2d1037 Mon Sep 17 00:00:00 2001 From: Patrick Rodacker Date: Sun, 10 Feb 2019 22:14:43 +0100 Subject: [PATCH 4/5] adds missing setIdentifierGenerator function to interface --- src/Grant/GrantTypeInterface.php | 8 ++++++++ 1 file changed, 8 insertions(+) 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); } From dc979d1ecc5bc65fd390c4f5c29cdd7abd903104 Mon Sep 17 00:00:00 2001 From: Patrick Rodacker Date: Sun, 10 Feb 2019 22:14:50 +0100 Subject: [PATCH 5/5] adds missing phpdoc block --- src/Grant/AbstractGrant.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index b3b66432b..fc7f86c71 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -169,6 +169,9 @@ public function setDefaultScope($scope) $this->defaultScope = $scope; } + /** + * @param IdentifierGeneratorInterface $identifierGenerator + */ public function setIdentifierGenerator(IdentifierGeneratorInterface $identifierGenerator) { $this->identifierGenerator = $identifierGenerator;