diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 1122749b..f8674004 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Grant\AbstractAuthorizeGrant; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -120,11 +121,14 @@ class AuthorizationServer implements EmitterAwareInterface $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); - $grantType->setDefaultScope($this->defaultScope); $grantType->setPrivateKey($this->privateKey); $grantType->setEmitter($this->getEmitter()); $grantType->setEncryptionKey($this->encryptionKey); + if ($grantType instanceof AbstractAuthorizeGrant) { + $grantType->setDefaultScope($this->defaultScope); + } + $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 6a8d7c07..0362fa22 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -11,6 +11,8 @@ namespace League\OAuth2\Server\Grant; +use League\OAuth2\Server\Exception\OAuthServerException; + abstract class AbstractAuthorizeGrant extends AbstractGrant { /** @@ -39,4 +41,17 @@ abstract class AbstractAuthorizeGrant extends AbstractGrant { $this->defaultScope = $scope; } + + /** + * @param ScopeEntityInterface[] $requestedScopes + * @param string $redirectUri + * + * @throws OAuthServerException + */ + protected function checkScopesRequested($requestedScopes, $redirectUri = null) + { + if (empty($requestedScopes)) { + throw OAuthServerException::invalidScope($redirectUri); + } + } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 297bce2b..b4f121da 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -232,10 +232,6 @@ abstract class AbstractGrant implements GrantTypeInterface $validScopes[] = $scope; } - if (empty($validScopes)) { - throw OAuthServerException::invalidScope($redirectUri); - } - return $validScopes; } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a8528bb5..e26b94aa 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -242,13 +242,19 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } } + $redirectUri = is_array($client->getRedirectUri()) ? $client->getRedirectUri()[0] : $client->getRedirectUri(); + $scopes = $this->validateScopes( $this->getQueryStringParameter('scope', $request, $this->defaultScope), - is_array($client->getRedirectUri()) - ? $client->getRedirectUri()[0] - : $client->getRedirectUri() + $redirectUri ); + try { + $this->checkScopesRequested($scopes, $redirectUri); + } catch (OAuthServerException $ex) { + throw $ex; + } + $stateParameter = $this->getQueryStringParameter('state', $request); $authorizationRequest = new AuthorizationRequest(); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 9f000eb0..5e102f32 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -144,13 +144,19 @@ class ImplicitGrant extends AbstractAuthorizeGrant } } + $redirectUri = is_array($client->getRedirectUri()) ? $client->getRedirectUri()[0] : $client->getRedirectUri(); + $scopes = $this->validateScopes( $this->getQueryStringParameter('scope', $request, $this->defaultScope), - is_array($client->getRedirectUri()) - ? $client->getRedirectUri()[0] - : $client->getRedirectUri() + $redirectUri ); + try { + $this->checkScopesRequested($scopes, $redirectUri); + } catch (OAuthServerException $ex) { + throw $ex; + } + // Finalize the requested scopes $finalizedScopes = $this->scopeRepository->finalizeScopes( $scopes, diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 83009716..542c78dc 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -459,21 +459,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $grantMock->validateScopes('basic '); } - /** - * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 5 - */ - public function testValidateScopesMissingScope() - { - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn(null); - - $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); - $grantMock->setScopeRepository($scopeRepositoryMock); - - $grantMock->validateScopes(''); - } - public function testGenerateUniqueIdentifier() { $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 025135c3..0e85144f 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -1656,16 +1656,45 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException \LogicException + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException ++ * @expectedExceptionCode 5 */ - public function testCompleteAuthorizationRequestNoUser() + public function testValidateAuthorizationRequestFailsWithoutScope() { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $scope = new ScopeEntity(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + $grant = new AuthCodeGrant( $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); - $grant->completeAuthorizationRequest(new AuthorizationRequest()); + $grant->setClientRepository($clientRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + [], + [], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); } } diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 8ad7e2b7..299cf020 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -9,14 +9,11 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; -use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase { - const DEFAULT_SCOPE = 'basic'; - public function testGetIdentifier() { $grant = new ClientCredentialsGrant(); @@ -33,16 +30,13 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $scope = new ScopeEntity(); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); $grant = new ClientCredentialsGrant(); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setDefaultScope(self::DEFAULT_SCOPE); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 18cb04b8..5009c605 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -411,4 +411,42 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->completeAuthorizationRequest(new AuthorizationRequest()); } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 5 + */ + public function testValidateAuthorizationRequestFailsWithoutScope() + { + $client = new ClientEntity(); + $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); + + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->setClientRepository($clientRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); + } } diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index ae4b311d..b380bfb2 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -13,15 +13,12 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; -use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Zend\Diactoros\ServerRequest; class PasswordGrantTest extends \PHPUnit_Framework_TestCase { - const DEFAULT_SCOPE = 'basic'; - public function testGetIdentifier() { $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); @@ -49,16 +46,13 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); - $scope = new ScopeEntity(); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setDefaultScope(self::DEFAULT_SCOPE); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index dbaf75d1..47d7ad17 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -20,8 +20,6 @@ use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { - const DEFAULT_SCOPE = 'basic'; - /** * @var CryptTraitStub */ @@ -49,7 +47,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeEntity = new ScopeEntity(); - $scopeEntity->setIdentifier(self::DEFAULT_SCOPE); $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); @@ -70,7 +67,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setDefaultScope(self::DEFAULT_SCOPE); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -78,7 +74,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'client_id' => 'foo', 'refresh_token_id' => 'zyxwvu', 'access_token_id' => 'abcdef', - 'scopes' => [self::DEFAULT_SCOPE], + 'scopes' => ['foo'], 'user_id' => 123, 'expire_time' => time() + 3600, ] diff --git a/tests/Middleware/AuthorizationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php index 1556405a..74dffbf7 100644 --- a/tests/Middleware/AuthorizationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -11,24 +11,18 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; -use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase { - - const DEFAULT_SCOPE = 'basic'; - public function testValidResponse() { $clientRepository = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepository->method('getClientEntity')->willReturn(new ClientEntity()); - $scope = new ScopeEntity(); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); $accessRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); @@ -43,7 +37,6 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase new StubResponseType() ); - $server->setDefaultScope(self::DEFAULT_SCOPE); $server->enableGrantType(new ClientCredentialsGrant()); $_POST['grant_type'] = 'client_credentials';