diff --git a/src/Entities/Traits/ClientTrait.php b/src/Entities/Traits/ClientTrait.php index bf5fb97d..db01649d 100644 --- a/src/Entities/Traits/ClientTrait.php +++ b/src/Entities/Traits/ClientTrait.php @@ -12,6 +12,7 @@ trait ClientTrait * Get the client's name. * * @return string + * @codeCoverageIgnore */ public function getName() { diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 1f08919c..2e4d8e18 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -119,6 +119,8 @@ class OAuthServerException extends \Exception * @param $hint * * @return static + * + * @codeCoverageIgnore */ public static function serverError($hint) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f3a5611..92cefe44 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -234,6 +234,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ] ) ); + $redirectPayload['state'] = $authorizationRequest->getState(); $response = new RedirectResponse(); $response->setRedirectUri( diff --git a/src/RequestEvent.php b/src/RequestEvent.php index d8f7da08..3170beab 100644 --- a/src/RequestEvent.php +++ b/src/RequestEvent.php @@ -26,6 +26,7 @@ class RequestEvent extends Event /** * @return ServerRequestInterface + * @codeCoverageIgnore */ public function getRequest() { diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php index 364d712f..d0ada49e 100644 --- a/tests/CryptTraitTest.php +++ b/tests/CryptTraitTest.php @@ -44,4 +44,12 @@ class CryptTraitTest extends \PHPUnit_Framework_TestCase $this->cryptStub->setPublicKey(new CryptKey(__DIR__ . '/Stubs/private.key')); $this->cryptStub->doDecrypt(''); } + + /** + * @expectedException \LogicException + */ + public function testNonExistentKey() + { + new CryptKey('foo/bar'); + } } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 1321654d..0c4f6ae7 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -13,6 +13,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; @@ -402,4 +403,28 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue(is_string($method->invoke($grantMock))); } + + public function testCanRespondToAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $this->assertFalse($grantMock->canRespondToAuthorizationRequest(new ServerRequest())); + } + + /** + * @expectedException \LogicException + */ + public function testValidateAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->validateAuthorizationRequest(new ServerRequest()); + } + + /** + * @expectedException \LogicException + */ + public function testCompleteAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->completeAuthorizationRequest(new AuthorizationRequest()); + } } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 4acfba9b..93dfcae6 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -24,7 +24,6 @@ use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index d5f82594..d9302cae 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -36,7 +37,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase new StubResponseType() ); - $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + $server->enableGrantType(new ClientCredentialsGrant()); $_POST['grant_type'] = 'client_credentials'; $_POST['client_id'] = 'foo'; @@ -89,4 +90,22 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->assertEquals(401, $response->getStatusCode()); } + + public function testOAuthErrorResponseRedirectUri() + { + $exception = OAuthServerException::invalidScope('test', 'http://foo/bar'); + $response = $exception->generateHttpResponse(new Response()); + + $this->assertEquals(302, $response->getStatusCode()); + $this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + } + + public function testOAuthErrorResponseRedirectUriFragment() + { + $exception = OAuthServerException::invalidScope('test', 'http://foo/bar'); + $response = $exception->generateHttpResponse(new Response(), true); + + $this->assertEquals(302, $response->getStatusCode()); + $this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + } } diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 5656d3d1..a71dc5ab 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -57,6 +57,47 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->assertEquals(200, $response->getStatusCode()); } + public function testValidResponseExpiredToken() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', + new StubResponseType() + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('test'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->sub(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $token = $accessToken->convertToJWT(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $token)); + + $middleware = new ResourceServerMiddleware($server); + $response = $middleware->__invoke( + $request, + new Response(), + function () { + $this->assertEquals('test', func_get_args()[0]->getAttribute('oauth_access_token_id')); + + return func_get_args()[1]; + } + ); + + $this->assertEquals(401, $response->getStatusCode()); + } + public function testErrorResponse() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 82d07059..2505d5e4 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,6 +2,7 @@ namespace LeagueTests; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; @@ -11,6 +12,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; use LeagueTests\Stubs\AccessTokenEntity; @@ -20,6 +22,7 @@ use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; +use Zend\Diactoros\ServerRequest; use Zend\Diactoros\ServerRequestFactory; class ServerTest extends \PHPUnit_Framework_TestCase @@ -74,57 +77,6 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals(200, $response->getStatusCode()); } - public function testRespondToRequestPsrResponse() - { - $client = new ClientEntity(); - $client->setIdentifier('foo'); - $client->setIdentifier('http://bar.com'); - - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - $clientRepository->method('getClientEntity')->willReturn($client); - - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); - - $server = new Server( - $clientRepository, - $this->getMock(AccessTokenRepositoryInterface::class), - $scopeRepositoryMock, - 'file://' . __DIR__ . '/Stubs/private.key', - 'file://' . __DIR__ . '/Stubs/public.key', - new StubResponseType() - ); - - $userRepository = $this->getMock(UserRepositoryInterface::class); - $userRepository->method('getUserEntityByUserCredentials')->willReturn(new UserEntity()); - - $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); - $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); - - $server->enableGrantType( - new AuthCodeGrant( - $authCodeRepoMock, - $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepository, - new \DateInterval('PT1H') - ), - new \DateInterval('PT1M') - ); - - $_SERVER['HTTP_HOST'] = 'http://auth.com'; - $_SERVER['REQUEST_URI'] = '/auth'; - $_GET['response_type'] = 'code'; - $_GET['client_id'] = $client->getIdentifier(); - $_GET['redirect_uri'] = $client->getRedirectUri(); - $_POST['action'] = 'approve'; - $_POST['username'] = 'user'; - $_POST['password'] = 'pass'; - $response = $server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response); - $this->assertTrue($response instanceof ResponseInterface); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertTrue(strstr($response->getHeaderLine('location'), 'code=') !== false); - } - public function testGetResponseType() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); @@ -144,7 +96,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); } - public function testValidateRequest() + public function testValidateAuthenticatedRequest() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); @@ -162,4 +114,113 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Missing "Authorization" header', $e->getHint()); } } + + public function testCompleteAuthorizationRequest() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + + $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + + $grant = new AuthCodeGrant( + $authCodeRepository, + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/Stubs/public.key')); + + $server->enableGrantType($grant); + + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(true); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); + + $this->assertTrue( + $server->completeAuthorizationRequest($authRequest, new Response) instanceof ResponseInterface + ); + } + + public function testValidateAuthorizationRequest() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + + $server = new Server( + $clientRepositoryMock, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + $server->enableGrantType($grant); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + ] + ); + + $this->assertTrue($server->validateAuthorizationRequest($request) instanceof AuthorizationRequest); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 2 + */ + public function testValidateAuthorizationRequestUnregistered() + { + $server = new Server( + $this->getMock(ClientRepositoryInterface::class), + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + ] + ); + + $server->validateAuthorizationRequest($request); + } }