diff --git a/.gitattributes b/.gitattributes index 58a5e5e6..d85a794e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,8 +7,7 @@ /.travis.yml export-ignore .travis.yml export-ignore .scrutinizer.yml export-ignore -/codeception.yml export-ignore /phpunit.xml.dist export-ignore /CHANGELOG.md export-ignore /CONTRIBUTING.md export-ignore -/README.md export-ignore +/README.md export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3b5992e5..897c80b1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ phpunit.xml .idea /examples/vendor -/tests/_output examples/public.key examples/private.key +build diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..6caf80c5 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,53 @@ +preset: psr2 + +enabled: + - binary_operator_spaces + - blank_line_before_return + - concat_with_spaces + - function_typehint_space + - hash_to_slash_comment + - include + - lowercase_cast + - method_separation + - native_function_casing + - no_blank_lines_after_class_opening + - no_blank_lines_between_uses + - no_duplicate_semicolons + - no_leading_import_slash + - no_leading_namespace_whitespace + - no_multiline_whitespace_before_semicolons + - no_php4_constructor + - no_short_bool_cast + - no_singleline_whitespace_before_semicolons + - no_trailing_comma_in_singleline_array + - no_unreachable_default_argument_value + - no_unused_imports + - no_whitespace_before_comma_in_array + - ordered_imports + - phpdoc_align + - phpdoc_indent + - phpdoc_inline_tag + - phpdoc_no_access + - phpdoc_no_simplified_null_return + - phpdoc_order + - phpdoc_property + - phpdoc_scalar + - phpdoc_separation + - phpdoc_to_comment + - phpdoc_trim + - phpdoc_type_to_var + - phpdoc_types + - phpdoc_var_without_name + - print_to_echo + - short_array_syntax + - short_scalar_cast + - simplified_null_return + - single_quote + - spaces_cast + - standardize_not_equal + - ternary_operator_spaces + - trailing_comma_in_multiline_array + - trim_array_spaces + - unary_operator_spaces + - whitespace_after_comma_in_array + - whitespacy_lines diff --git a/.travis.yml b/.travis.yml index 9ab34bb5..3ebf76cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,37 +15,10 @@ php: install: - travis_retry composer install --no-interaction --prefer-source -before_script: - - cd examples/ - - composer install - - cd public/ - - php -S localhost:7777 & - - cd ../.. - script: - - vendor/bin/codecept build && vendor/bin/codecept run - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover - - git config --global user.email "travis@travis-ci.org" - - git config --global user.name "TravisCI" - - cp -R coverage ${HOME}/coverage - - cd ${HOME} - - git clone --quiet --branch=gh-pages https://${GITHUBTOKEN}@github.com/thephpleague/oauth2-server.git gh-pages > /dev/null - - cd gh-pages - - mkdir ${TRAVIS_BRANCH} - - cd ${TRAVIS_BRANCH} - - cp -Rf $HOME/coverage/* . - - git add -f . - - git commit -m "Travis pushed coverage of ${TRAVIS_COMMIT}@${TRAVIS_BRANCH} to gh-pages" - - git push -fq origin gh-pages > /dev/null + - vendor/bin/phpunit branches: only: - master - - v5 - -env: - global: - secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg=" \ No newline at end of file + - V5-WIP \ No newline at end of file diff --git a/README.md b/README.md index 8c3c3ca1..29e0e0e2 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,19 @@ [![Build Status](https://img.shields.io/travis/thephpleague/oauth2-server/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/oauth2-server) [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure) [![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server) -[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thephpleague/oauth2-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server) `league/oauth2-server` is a a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them. It supports out of the box the following grants: * Authorization code grant +* Implicit grant * Client credentials grant * Resource owner password credentials grant * Refresh grant -You can also define your own grants. +You can also easily define your own grants. In addition it supports the following token response types: @@ -49,7 +50,9 @@ Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/ ## Support -Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues) +Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues). + +If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below. ## Security diff --git a/codeception.yml b/codeception.yml deleted file mode 100644 index 35fa7fde..00000000 --- a/codeception.yml +++ /dev/null @@ -1,10 +0,0 @@ -actor: Tester -paths: - tests: tests - log: tests/_output - data: tests/_data - helpers: tests/_support -settings: - bootstrap: _bootstrap.php - colors: true - memory_limit: 1024M \ No newline at end of file diff --git a/composer.json b/composer.json index 55357050..67e551a9 100644 --- a/composer.json +++ b/composer.json @@ -11,10 +11,8 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "4.8.*", - "mockery/mockery": "0.9.*", - "codeception/codeception": "~2.0", - "flow/jsonpath": "0.2.*" + "phpunit/phpunit": "^4.8", + "league/plates": "^3.1" }, "repositories": [ { @@ -57,7 +55,7 @@ }, "autoload-dev": { "psr-4": { - "LeagueTests\\": "tests/unit/" + "LeagueTests\\": "tests/" } }, "extra": { diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 357fc626..824b72d6 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -14,7 +14,7 @@ use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Zend\Diactoros\Stream; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__ . '/../vendor/autoload.php'; $app = new App([ 'settings' => [ @@ -56,6 +56,22 @@ $app = new App([ }, ]); +$app->any('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { + /* @var \League\OAuth2\Server\Server $server */ + $server = $app->getContainer()->get(Server::class); + + try { + return $server->respondToRequest($request, $response); + } catch (OAuthServerException $exception) { + return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + $body = new Stream('php://temp', 'r+'); + $body->write($exception->getMessage()); + + return $response->withStatus(500)->withBody($body); + } +}); + $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { /* @var \League\OAuth2\Server\Server $server */ $server = $app->getContainer()->get(Server::class); diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index b6a1600a..1792eb69 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -11,7 +11,7 @@ use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Zend\Diactoros\Stream; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__ . '/../vendor/autoload.php'; $app = new App([ 'settings' => [ @@ -42,7 +42,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { diff --git a/examples/public/middleware.php b/examples/public/middleware_use.php similarity index 98% rename from examples/public/middleware.php rename to examples/public/middleware_use.php index 3ace6072..9597c2d7 100644 --- a/examples/public/middleware.php +++ b/examples/public/middleware_use.php @@ -16,7 +16,7 @@ use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Zend\Diactoros\Stream; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__ . '/../vendor/autoload.php'; $app = new App([ 'settings' => [ @@ -61,7 +61,7 @@ $app = new App([ ); return $server; - } + }, ]); // Access token issuer diff --git a/examples/public/password.php b/examples/public/password.php index 72992536..c04c0e91 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -13,7 +13,7 @@ use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Zend\Diactoros\Stream; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__ . '/../vendor/autoload.php'; $app = new App([ 'settings' => [ @@ -46,7 +46,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 041131b5..a5e80047 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -12,7 +12,7 @@ use Psr\Http\Message\ServerRequestInterface; use Slim\App; use Zend\Diactoros\Stream; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__ . '/../vendor/autoload.php'; $app = new App([ 'settings' => [ diff --git a/examples/public/secured_route.php b/examples/public/secured_route.php deleted file mode 100644 index c98a8313..00000000 --- a/examples/public/secured_route.php +++ /dev/null @@ -1,72 +0,0 @@ - [ - 'displayErrorDetails' => true, - ], - Server::class => function () { - // Init our repositories - $clientRepository = new ClientRepository(); - $accessTokenRepository = new AccessTokenRepository(); - $scopeRepository = new ScopeRepository(); - - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; - - // Setup the authorization server - return new Server( - $clientRepository, - $accessTokenRepository, - $scopeRepository, - $privateKeyPath, - $publicKeyPath - ); - } -]); - -$app->get('/user', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - $server = $app->getContainer()->get(Server::class); - $body = new Stream('php://temp', 'r+'); - - try { - $request = $server->validateRequest($request); - } catch (OAuthServerException $exception) { - return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { - $body->write($exception->getMessage()); - - return $response->withStatus(500)->withBody($body); - } - - $params = []; - - if (in_array('basic', $request->getAttribute('oauth_scopes', []))) { - $params = [ - 'id' => 1, - 'name' => 'Alex', - 'city' => 'London' - ]; - } - - if (in_array('email', $request->getAttribute('oauth_scopes', []))) { - $params['email'] = 'alex@example.com'; - } - - $body->write(json_encode($params)); - - return $response->withBody($body); -}); - -$app->run(); diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php index 8feb8c73..9efe6611 100644 --- a/examples/src/Entities/UserEntity.php +++ b/examples/src/Entities/UserEntity.php @@ -7,11 +7,12 @@ use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; class UserEntity implements UserEntityInterface { /** - * Return the user's identifier + * Return the user's identifier. + * * @return mixed */ public function getIdentifier() { return 1; } -} \ No newline at end of file +} diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index bc8ada68..5a58c915 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -1,4 +1,5 @@ [ 'secret' => password_hash('abc123', PASSWORD_BCRYPT), 'name' => 'My Awesome App', - 'redirect_uri' => 'http://foo/bar' - ] + 'redirect_uri' => 'http://foo/bar', + ], ]; // Check if client is registered if (array_key_exists($clientIdentifier, $clients) === false) { - return null; + return; } // Check if client secret is valid if ($clientSecret !== null && password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false) { - return null; + return; } // Check if redirect URI is valid if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirect_uri']) { - return null; + return; } $client = new ClientEntity(); diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php index a7a4e079..15f19ddf 100644 --- a/examples/src/Repositories/RefreshTokenRepository.php +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -7,9 +7,8 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; class RefreshTokenRepository implements RefreshTokenRepositoryInterface { - /** - * Create a new refresh token_name + * Create a new refresh token_name. * * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntityInterface */ @@ -19,7 +18,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * Revoke the refresh token + * Revoke the refresh token. * * @param string $tokenId */ @@ -29,7 +28,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * Check if the refresh token has been revoked + * Check if the refresh token has been revoked. * * @param string $tokenId * diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index ecfadd11..f48aac5b 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -1,4 +1,5 @@ [ - 'description' => 'Basic details about you' + 'description' => 'Basic details about you', ], 'email' => [ - 'description' => 'Your email address' - ] + 'description' => 'Your email address', + ], ]; if (array_key_exists($scopeIdentifier, $scopes) === false) { - return null; + return; } $scope = new ScopeEntity(); diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 1ad9914d..ec930500 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -1,4 +1,5 @@ - - - - ./tests/unit/ - - - - - src - - - - - - + + + + ./tests/ + + + + + src + + src/ResponseTypes/DefaultTemplates + + + + + + + diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index 830c13e1..75bcb4c6 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -1,6 +1,9 @@ setAudience($this->getClient()->getIdentifier()) + ->setId($this->getIdentifier(), true) + ->setIssuedAt(time()) + ->setNotBefore(time()) + ->setExpiration($this->getExpiryDateTime()->getTimestamp()) + ->setSubject($this->getUserIdentifier()) + ->set('scopes', $this->getScopes()) + ->sign(new Sha256(), new Key($pathToPrivateKey)) + ->getToken(); + } } diff --git a/src/Entities/AuthCodeEntity.php b/src/Entities/AuthCodeEntity.php index 7e49317f..87279d30 100644 --- a/src/Entities/AuthCodeEntity.php +++ b/src/Entities/AuthCodeEntity.php @@ -1,4 +1,5 @@ clientId; - } - - /** - * @return null|string - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * @return null|string - */ - public function getScope() - { - return $this->scope; - } - - /** - * @return null|string - */ - public function getState() - { - return $this->state; - } - - /** - * AuthorizationCodeRequestEntity constructor. - * - * @param string $clientId - * @param string|null $redirectUri - * @param string|null $scope - * @param string|null $state - */ - public function __construct($clientId, $redirectUri = null, $scope = null, $state = null) - { - $this->clientId = $clientId; - $this->redirectUri = $redirectUri; - $this->scope = $scope; - $this->state = $state; - } - - public function __sleep() - { - return ['clientId', 'redirectUri', 'scope', 'state']; - } -} diff --git a/src/Entities/ClientEntity.php b/src/Entities/ClientEntity.php index a8840250..d72b6b3f 100644 --- a/src/Entities/ClientEntity.php +++ b/src/Entities/ClientEntity.php @@ -1,4 +1,5 @@ name = $name; } + + /** + * {@inheritdoc} + */ + public function canKeepASecret() + { + return $this->secret !== null; + } + + /** + * {@inheritdoc} + */ + public function setSecret($secret) + { + $this->secret = $secret; + } + + /** + * {@inheritdoc} + */ + public function validateSecret($submittedSecret) + { + return strcmp((string) $submittedSecret, $this->secret) === 0; + } + + /** + * {@inheritdoc} + */ + public function setRedirectUri($redirectUri) + { + $this->redirectUri = $redirectUri; + } + + /** + * {@inheritdoc} + */ + public function getRedirectUri() + { + return $this->redirectUri; + } } diff --git a/src/Entities/Traits/EntityTrait.php b/src/Entities/Traits/EntityTrait.php index 527506ac..7142e5fe 100644 --- a/src/Entities/Traits/EntityTrait.php +++ b/src/Entities/Traits/EntityTrait.php @@ -1,4 +1,5 @@ expiryDateTime = $dateTime; } + + /** + * Has the token expired? + * + * @return bool + */ + public function isExpired() + { + return (new DateTime()) > $this->getExpiryDateTime(); + } } diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index 324de912..35230b26 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -1,4 +1,5 @@ httpStatusCode = $httpStatusCode; $this->errorType = $errorType; $this->hint = $hint; @@ -48,125 +49,89 @@ class OAuthServerException extends \Exception } /** - * Invalid grant type error - * - * @param null|string $localizedError - * @param null|string $localizedHint + * Invalid grant type error. * * @return static */ - public static function invalidGrantType( - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The provided authorization grant is invalid, expired, revoked, does not match ' . - 'the redirection URI used in the authorization request, or was issued to another client.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? 'Check the `grant_type` parameter' - : $localizedHint; + public static function invalidGrantType() + { + $errorMessage = 'The provided authorization grant is invalid, expired, revoked, does not match ' . + 'the redirection URI used in the authorization request, or was issued to another client.'; + $hint = 'Check the `grant_type` parameter'; - return new static($errorMessage, 'invalid_grant', 400, $hint); + return new static($errorMessage, 1, 'invalid_grant', 400, $hint); } /** - * Unsupported grant type error - * - * @param null|string $localizedError - * @param null|string $localizedHint + * Unsupported grant type error. * * @return static */ - public static function unsupportedGrantType( - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The authorization grant type is not supported by the authorization server.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? 'Check the `grant_type` parameter' - : $localizedHint; + public static function unsupportedGrantType() + { + $errorMessage = 'The authorization grant type is not supported by the authorization server.'; + $hint = 'Check the `grant_type` parameter'; - return new static($errorMessage, 'unsupported_grant_type', 400, $hint); + return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint); } /** - * Invalid request error + * Invalid request error. * * @param string $parameter The invalid parameter - * @param null|string $localizedError - * @param null|string $localizedHint + * @param string|null $hint * * @return static */ - public static function invalidRequest( - $parameter, - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The request is missing a required parameter, includes an invalid parameter value, ' . - 'includes a parameter more than once, or is otherwise malformed.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? sprintf('Check the `%s` parameter', $parameter) - : sprintf($localizedHint, $parameter); - - return new static($errorMessage, 'invalid_request', 400, $hint); - } - - /** - * Invalid client error - * - * @param null|string $localizedError - * - * @return static - */ - public static function invalidClient($localizedError = null) + public static function invalidRequest($parameter, $hint = null) { - $errorMessage = (is_null($localizedError)) - ? 'Client authentication failed' - : $localizedError; + $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' . + 'includes a parameter more than once, or is otherwise malformed.'; + $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint; - return new static($errorMessage, 'invalid_client', 401); + return new static($errorMessage, 3, 'invalid_request', 400, $hint); } /** - * Invalid scope error - * - * @param string $scope The bad scope - * @param null|string $localizedError A localized error message - * @param null|string $localizedHint A localized error hint - * @param null|string $redirectUri A HTTP URI to redirect the user back to + * Invalid client error. * * @return static */ - public static function invalidScope($scope, $localizedError = null, $localizedHint = null, $redirectUri = null) + public static function invalidClient() { - $errorMessage = (is_null($localizedError)) - ? 'The requested scope is invalid, unknown, or malformed' - : $localizedError; - $hint = (is_null($localizedHint)) - ? sprintf('Check the `%s` scope', $scope) - : sprintf($localizedHint, $scope); + $errorMessage = 'Client authentication failed'; - return new static($errorMessage, 'invalid_scope', 400, $hint, $redirectUri); + return new static($errorMessage, 4, 'invalid_client', 401); } /** - * Invalid credentials error + * Invalid scope error. + * + * @param string $scope The bad scope + * @param null|string $redirectUri A HTTP URI to redirect the user back to + * + * @return static + */ + public static function invalidScope($scope, $redirectUri = null) + { + $errorMessage = 'The requested scope is invalid, unknown, or malformed'; + $hint = sprintf('Check the `%s` scope', $scope); + + return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri); + } + + /** + * Invalid credentials error. * * @return static */ public static function invalidCredentials() { - return new static('The user credentials were incorrect.', 'invalid_credentials', 401); + return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401); } /** - * Server error + * Server error. * * @param $hint * @@ -176,26 +141,27 @@ class OAuthServerException extends \Exception { return new static( 'The authorization server encountered an unexpected condition which prevented it from fulfilling' - . 'the request.', + . ' the request: ' . $hint, + 7, 'server_error', - 500, - $hint + 500 ); } /** - * Invalid refresh token + * Invalid refresh token. * * @param string|null $hint + * * @return static */ public static function invalidRefreshToken($hint = null) { - return new static('The refresh token is invalid.', 'invalid_request', 400, $hint); + return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint); } /** - * Access denied + * Access denied. * * @param string|null $hint * @param string|null $redirectUri @@ -206,6 +172,7 @@ class OAuthServerException extends \Exception { return new static( 'The resource owner or authorization server denied the request.', + 9, 'access_denied', 401, $hint, @@ -222,13 +189,15 @@ class OAuthServerException extends \Exception } /** - * Generate a HTTP response + * Generate a HTTP response. * * @param \Psr\Http\Message\ResponseInterface $response + * @param bool $useFragment True if errors should be in the URI fragment instead of + * query string * * @return \Psr\Http\Message\ResponseInterface */ - public function generateHttpResponse(ResponseInterface $response = null) + public function generateHttpResponse(ResponseInterface $response = null, $useFragment = false) { if (!$response instanceof ResponseInterface) { $response = new Response(); @@ -238,7 +207,7 @@ class OAuthServerException extends \Exception $payload = [ 'error' => $this->errorType, - 'message' => $this->getMessage() + 'message' => $this->getMessage(), ]; if ($this->hint !== null) { @@ -249,9 +218,15 @@ class OAuthServerException extends \Exception $redirectUri = new Uri($this->redirectUri); parse_str($redirectUri->getQuery(), $redirectPayload); - $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( - array_merge($redirectPayload, $payload) - )); + if ($useFragment === true) { + $headers['Location'] = (string) $redirectUri->withFragment(http_build_query( + array_merge($redirectPayload, $payload) + )); + } else { + $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( + array_merge($redirectPayload, $payload) + )); + } } foreach ($headers as $header => $content) { @@ -264,14 +239,14 @@ class OAuthServerException extends \Exception } /** - * Get all headers that have to be send with the error response + * Get all headers that have to be send with the error response. * * @return array Array with header values */ public function getHttpHeaders() { $headers = [ - 'Content-type' => 'application/json' + 'Content-type' => 'application/json', ]; // Add "WWW-Authenticate" header @@ -312,7 +287,7 @@ class OAuthServerException extends \Exception } /** - * Returns the HTTP status code to send when the exceptions is output + * Returns the HTTP status code to send when the exceptions is output. * * @return int */ @@ -320,4 +295,12 @@ class OAuthServerException extends \Exception { return $this->httpStatusCode; } + + /** + * @return null|string + */ + public function getHint() + { + return $this->hint; + } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 39fbf543..a7b5fbd1 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; @@ -21,13 +20,15 @@ use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +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\Utils\SecureKey; +use OAuth2ServerExamples\Repositories\AuthCodeRepository; use Psr\Http\Message\ServerRequestInterface; /** - * Abstract grant class + * Abstract grant class. */ abstract class AbstractGrant implements GrantTypeInterface { @@ -35,13 +36,6 @@ abstract class AbstractGrant implements GrantTypeInterface const SCOPE_DELIMITER_STRING = ' '; - /** - * Grant responds with - * - * @var string - */ - protected $respondsWith = 'token'; - /** * @var ServerRequestInterface */ @@ -62,6 +56,16 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $scopeRepository; + /** + * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface + */ + private $authCodeRepository; + + /** + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + */ + private $refreshTokenRepository; + /** * @var string */ @@ -101,6 +105,22 @@ abstract class AbstractGrant implements GrantTypeInterface $this->scopeRepository = $scopeRepository; } + /** + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + */ + public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository) + { + $this->refreshTokenRepository = $refreshTokenRepository; + } + + /** + * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository + */ + public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository) + { + $this->authCodeRepository = $authCodeRepository; + } + /** * @param string $pathToPrivateKey */ @@ -118,7 +138,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setEmitter(EmitterInterface $emitter = null) { @@ -126,7 +146,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL) { @@ -134,61 +154,69 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * {@inheritdoc} + * @return AuthCodeRepositoryInterface */ - public function respondsWith() + protected function getAuthCodeRepository() { - return $this->respondsWith; + return $this->authCodeRepository; } /** - * Validate the client + * @return RefreshTokenRepositoryInterface + */ + protected function getRefreshTokenRepository() + { + return $this->refreshTokenRepository; + } + + /** + * Validate the client. * * @param \Psr\Http\Message\ServerRequestInterface $request - * @param bool $validateSecret - * @param bool $validateRedirectUri + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface - * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateClient( - ServerRequestInterface $request, - $validateSecret = true, - $validateRedirectUri = false - ) { + protected function validateClient(ServerRequestInterface $request) + { $clientId = $this->getRequestParameter( 'client_id', $request, $this->getServerParameter('PHP_AUTH_USER', $request) ); if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing'); } + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); + + if (!$client instanceof ClientEntityInterface) { + throw OAuthServerException::invalidClient(); + } + + // If the client is confidential require the client secret $clientSecret = $this->getRequestParameter( 'client_secret', $request, $this->getServerParameter('PHP_AUTH_PW', $request) ); - if (is_null($clientSecret) && $validateSecret === true) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); + + if ($client->canKeepASecret() && is_null($clientSecret)) { + throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing'); } - $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); - if (is_null($redirectUri) && $validateRedirectUri === true) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); - } - - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - $redirectUri, - $this->getIdentifier() - ); - - if (!$client instanceof ClientEntityInterface) { + if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } + // If a redirect URI is provided ensure it matches what is pre-registered + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + if ($redirectUri !== null && (strcmp($client->getRedirectUri(), $redirectUri) !== 0)) { throw OAuthServerException::invalidClient(); } @@ -196,15 +224,15 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Validate scopes in the request + * Validate scopes in the request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $redirectUri * - * @return \League\OAuth2\Server\Entities\ScopeEntity[] - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\ScopeEntity[] */ public function validateScopes( ServerRequestInterface $request, @@ -228,7 +256,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if (($scope instanceof ScopeEntity) === false) { - throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri); + throw OAuthServerException::invalidScope($scopeItem, $redirectUri); } $scopes[] = $scope; @@ -294,7 +322,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Issue an access token + * Issue an access token. * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client @@ -310,20 +338,27 @@ abstract class AbstractGrant implements GrantTypeInterface array $scopes = [] ) { $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setIdentifier($this->generateUniqueIdentifier()); $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $accessToken->setClient($client); $accessToken->setUserIdentifier($userIdentifier); foreach ($scopes as $scope) { + if (is_string($scope)) { + $s = new ScopeEntity(); + $s->setIdentifier($scope); + $scope = $s; + } $accessToken->addScope($scope); } + $this->accessTokenRepository->persistNewAccessToken($accessToken); + return $accessToken; } /** - * Issue an auth code + * Issue an auth code. * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client @@ -331,8 +366,9 @@ abstract class AbstractGrant implements GrantTypeInterface * @param string $redirectUri * @param array $scopes * - * @return \League\OAuth2\Server\Entities\AuthCodeEntity * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\AuthCodeEntity */ protected function issueAuthCode( \DateInterval $tokenTTL, @@ -342,7 +378,7 @@ abstract class AbstractGrant implements GrantTypeInterface array $scopes = [] ) { $authCode = new AuthCodeEntity(); - $authCode->setIdentifier(SecureKey::generate()); + $authCode->setIdentifier($this->generateUniqueIdentifier()); $authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $authCode->setClient($client); $authCode->setUserIdentifier($userIdentifier); @@ -352,6 +388,8 @@ abstract class AbstractGrant implements GrantTypeInterface $authCode->addScope($scope); } + $this->authCodeRepository->persistNewAuthCode($authCode); + return $authCode; } @@ -363,21 +401,46 @@ abstract class AbstractGrant implements GrantTypeInterface protected function issueRefreshToken(AccessTokenEntity $accessToken) { $refreshToken = new RefreshTokenEntity(); - $refreshToken->setIdentifier(SecureKey::generate()); + $refreshToken->setIdentifier($this->generateUniqueIdentifier()); $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + return $refreshToken; } /** - * @inheritdoc + * Generate a new unique identifier. + * + * @param int $length + * + * @throws \League\OAuth2\Server\Exception\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'); + } catch (\Error $e) { + throw OAuthServerException::serverError('An unexpected error has occurred'); + } catch (\Exception $e) { + // If you get this message, the CSPRNG failed hard. + throw OAuthServerException::serverError('Could not generate a random string'); + } + // @codeCoverageIgnoreEnd + } + + /** + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { - return ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === $this->getIdentifier() - ); + return isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === $this->getIdentifier(); } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 560b8ad1..4d253488 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -12,7 +13,6 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; use League\Plates\Engine; -use League\Event\Event; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Uri; @@ -23,10 +23,6 @@ class AuthCodeGrant extends AbstractGrant * @var \DateInterval */ private $authCodeTTL; - /** - * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface - */ - private $authCodeRepository; /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface @@ -43,11 +39,6 @@ class AuthCodeGrant extends AbstractGrant */ private $pathToAuthorizeTemplate; - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; - /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -64,27 +55,35 @@ class AuthCodeGrant extends AbstractGrant $pathToLoginTemplate = null, $pathToAuthorizeTemplate = null ) { - $this->authCodeRepository = $authCodeRepository; - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setAuthCodeRepository($authCodeRepository); + $this->setRefreshTokenRepository($refreshTokenRepository); $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; - $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' - : $this->pathToLoginTemplate; - $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' - : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); + + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + if ($pathToLoginTemplate !== null) { + $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') + ? substr($pathToLoginTemplate, 0, -4) + : $pathToLoginTemplate; + } + + $this->pathToAuthorizeTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client'; + if ($pathToAuthorizeTemplate !== null) { + $this->pathToAuthorizeTemplate = (substr($pathToAuthorizeTemplate, -4) === '.php') + ? substr($pathToAuthorizeTemplate, 0, -4) + : $pathToAuthorizeTemplate; + } } - /** - * Respond to an authorization request + * Respond to an authorization request. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \Psr\Http\Message\ResponseInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ResponseInterface */ protected function respondToAuthorizationRequest( ServerRequestInterface $request @@ -95,28 +94,26 @@ class AuthCodeGrant extends AbstractGrant $this->getServerParameter('PHP_AUTH_USER', $request) ); if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } - - $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); - if (is_null($redirectUri)) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_id'); } $client = $this->clientRepository->getClientEntity( $clientId, - null, - $redirectUri, $this->getIdentifier() ); if ($client instanceof ClientEntityInterface === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } - $scopes = $this->validateScopes($request, $client, $redirectUri); + $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); + if ($redirectUriParameter !== $client->getRedirectUri()) { + throw OAuthServerException::invalidClient(); + } + + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( sprintf( @@ -168,8 +165,9 @@ class AuthCodeGrant extends AbstractGrant // The user hasn't logged in yet so show a login form if ($userId === null) { $engine = new Engine(dirname($this->pathToLoginTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToLoginTemplate); $html = $engine->render( - 'login_user', + end($pathParts), [ 'error' => $loginError, 'postback_uri' => (string) $postbackUri->withQuery($queryString), @@ -179,12 +177,12 @@ class AuthCodeGrant extends AbstractGrant return new Response\HtmlResponse($html); } - // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToAuthorizeTemplate); $html = $engine->render( - 'authorize_client', + end($pathParts), [ 'client' => $client, 'scopes' => $scopes, @@ -210,14 +208,16 @@ class AuthCodeGrant extends AbstractGrant ); } - $stateParameter = $this->getQueryStringParameter('state', $request); - - $redirectUri = new Uri($redirectUri); + // The user has either approved or denied the client, so redirect them back + $redirectUri = new Uri($client->getRedirectUri()); parse_str($redirectUri->getQuery(), $redirectPayload); + + $stateParameter = $this->getQueryStringParameter('state', $request); if ($stateParameter !== null) { $redirectPayload['state'] = $stateParameter; } + // THe user approved the client, redirect them back with an auth code if ($userHasApprovedClient === true) { $authCode = $this->issueAuthCode( $this->authCodeTTL, @@ -226,12 +226,12 @@ class AuthCodeGrant extends AbstractGrant $redirectUri, $scopes ); - $this->authCodeRepository->persistNewAuthCode($authCode); $redirectPayload['code'] = KeyCrypt::encrypt( json_encode( [ 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), 'auth_code_id' => $authCode->getIdentifier(), 'scopes' => $authCode->getScopes(), 'user_id' => $authCode->getUserIdentifier(), @@ -244,25 +244,34 @@ class AuthCodeGrant extends AbstractGrant return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload))); } + // The user denied the client, redirect them back with an error $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + return $exception->generateHttpResponse(); } /** - * Respond to an access token request + * Respond to an access token request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \DateInterval $accessTokenTTL * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ protected function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, DateInterval $accessTokenTTL ) { + // The redirect URI is required in this request + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + if (is_null($redirectUri)) { + throw OAuthServerException::invalidRequest('redirect_uri'); + } + // Validate request $client = $this->validateClient($request); $encryptedAuthCode = $this->getRequestParameter('code', $request, null); @@ -278,15 +287,19 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } - if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { + if ($this->getAuthCodeRepository()->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked'); } if ($authCodePayload->client_id !== $client->getIdentifier()) { throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } + + if ($authCodePayload->redirect_uri !== $redirectUri) { + throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI'); + } } catch (\LogicException $e) { - throw OAuthServerException::invalidRequest('code', null, 'Cannot decrypt the authorization code'); + throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code'); } // Issue and persist access + refresh tokens @@ -297,8 +310,6 @@ class AuthCodeGrant extends AbstractGrant $authCodePayload->scopes ); $refreshToken = $this->issueRefreshToken($accessToken); - $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); // Inject tokens into response type $responseType->setAccessToken($accessToken); @@ -308,21 +319,20 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { - return ( + return ( isset($request->getQueryParams()['response_type']) && $request->getQueryParams()['response_type'] === 'code' && isset($request->getQueryParams()['client_id']) - ) || (parent::canRespondToRequest($request)) - ); + ) || (parent::canRespondToRequest($request)); } /** - * Return the grant identifier that can be used in matching up requests + * Return the grant identifier that can be used in matching up requests. * * @return string */ @@ -332,7 +342,7 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -340,18 +350,12 @@ class AuthCodeGrant extends AbstractGrant \DateInterval $accessTokenTTL ) { if ( - isset($request->getQueryParams()['response_type']) + array_key_exists('response_type', $request->getQueryParams()) && $request->getQueryParams()['response_type'] === 'code' - && isset($request->getQueryParams()['client_id']) ) { return $this->respondToAuthorizationRequest($request); - } elseif ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'authorization_code' - ) { - return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); - } else { - throw OAuthServerException::serverError('respondToRequest() should not have been called'); } + + return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); } } diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index cf6ce268..6da17f21 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -1,26 +1,25 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Client credentials grant class + * Client credentials grant class. */ class ClientCredentialsGrant extends AbstractGrant { /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -33,7 +32,6 @@ class ClientCredentialsGrant extends AbstractGrant // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); - $this->accessTokenRepository->persistNewAccessToken($accessToken); // Inject access token into response type $responseType->setAccessToken($accessToken); @@ -42,7 +40,7 @@ class ClientCredentialsGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 698639d9..5ddd81b8 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareInterface; @@ -19,33 +18,26 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Grant type interface + * Grant type interface. */ interface GrantTypeInterface extends EmitterAwareInterface { /** - * Set refresh token TTL + * Set refresh token TTL. * * @param \DateInterval $refreshTokenTTL */ public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL); /** - * Return the grant identifier that can be used in matching up requests + * Return the grant identifier that can be used in matching up requests. * * @return string */ public function getIdentifier(); /** - * Details what the grant responds with - * - * @return string - */ - public function respondsWith(); - - /** - * Respond to an incoming request + * Respond to an incoming request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType @@ -69,40 +61,40 @@ interface GrantTypeInterface extends EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return boolean + * @return bool */ public function canRespondToRequest(ServerRequestInterface $request); /** - * Set the client repository + * Set the client repository. * * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository */ public function setClientRepository(ClientRepositoryInterface $clientRepository); /** - * Set the access token repository + * Set the access token repository. * * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository */ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository); /** - * Set the scope repository + * Set the scope repository. * * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository */ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository); /** - * Set the path to the private key + * Set the path to the private key. * * @param string $pathToPrivateKey */ public function setPathToPrivateKey($pathToPrivateKey); /** - * Set the path to the public key + * Set the path to the public key. * * @param string $pathToPublicKey */ diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php new file mode 100644 index 00000000..8123550e --- /dev/null +++ b/src/Grant/ImplicitGrant.php @@ -0,0 +1,241 @@ +userRepository = $userRepository; + $this->refreshTokenTTL = new \DateInterval('P1M'); + + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + if ($pathToLoginTemplate !== null) { + $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') + ? substr($pathToLoginTemplate, 0, -4) + : $pathToLoginTemplate; + } + + $this->pathToAuthorizeTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client'; + if ($pathToAuthorizeTemplate !== null) { + $this->pathToAuthorizeTemplate = (substr($pathToAuthorizeTemplate, -4) === '.php') + ? substr($pathToAuthorizeTemplate, 0, -4) + : $pathToAuthorizeTemplate; + } + } + + /** + * {@inheritdoc} + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + return (array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'token'); + } + + /** + * Return the grant identifier that can be used in matching up requests. + * + * @return string + */ + public function getIdentifier() + { + return 'implicit'; + } + + /** + * {@inheritdoc} + */ + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + \DateInterval $accessTokenTTL + ) { + $clientId = $this->getQueryStringParameter( + 'client_id', + $request, + $this->getServerParameter('PHP_AUTH_USER', $request) + ); + if (is_null($clientId)) { + throw OAuthServerException::invalidRequest('client_id'); + } + + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); + + if ($client instanceof ClientEntityInterface === false) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + + throw OAuthServerException::invalidClient(); + } + + $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); + if ($redirectUriParameter !== $client->getRedirectUri()) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + + throw OAuthServerException::invalidClient(); + } + + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); + $queryString = http_build_query($request->getQueryParams()); + $postbackUri = new Uri( + sprintf( + '//%s%s', + $request->getServerParams()['HTTP_HOST'], + $request->getServerParams()['REQUEST_URI'] + ) + ); + + $userId = null; + $userHasApprovedClient = null; + if ($this->getRequestParameter('action', $request, null) !== null) { + $userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve'); + } + + // Check if the user has been authenticated + $oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null); + if ($oauthCookie !== null) { + try { + $oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey)); + if (is_object($oauthCookiePayload)) { + $userId = $oauthCookiePayload->user_id; + } + } catch (\LogicException $e) { + throw OAuthServerException::serverError($e->getMessage()); + } + } + + // The username + password might be available in $_POST + $usernameParameter = $this->getRequestParameter('username', $request, null); + $passwordParameter = $this->getRequestParameter('password', $request, null); + + $loginError = null; + + // Assert if the user has logged in already + if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) { + $userEntity = $this->userRepository->getUserEntityByUserCredentials( + $usernameParameter, + $passwordParameter + ); + + if ($userEntity instanceof UserEntityInterface) { + $userId = $userEntity->getIdentifier(); + } else { + $loginError = 'Incorrect username or password'; + } + } + + // The user hasn't logged in yet so show a login form + if ($userId === null) { + $engine = new Engine(dirname($this->pathToLoginTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToLoginTemplate); + $html = $engine->render( + end($pathParts), + [ + 'error' => $loginError, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ] + ); + + return new Response\HtmlResponse($html); + } + + // The user hasn't approved the client yet so show an authorize form + if ($userId !== null && $userHasApprovedClient === null) { + $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToAuthorizeTemplate); + $html = $engine->render( + end($pathParts), + [ + 'client' => $client, + 'scopes' => $scopes, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ] + ); + + return new Response\HtmlResponse( + $html, + 200, + [ + 'Set-Cookie' => sprintf( + 'oauth_authorize_request=%s; Expires=%s', + urlencode(KeyCrypt::encrypt( + json_encode([ + 'user_id' => $userId, + ]), + $this->pathToPrivateKey + )), + (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') + ), + ] + ); + } + + // The user has either approved or denied the client, so redirect them back + $redirectUri = new Uri($client->getRedirectUri()); + $redirectPayload = []; + + $stateParameter = $this->getQueryStringParameter('state', $request); + if ($stateParameter !== null) { + $redirectPayload['state'] = $stateParameter; + } + + // THe user approved the client, redirect them back with an access token + if ($userHasApprovedClient === true) { + $accessToken = $this->issueAccessToken( + $accessTokenTTL, + $client, + $userId, + $scopes + ); + + $redirectPayload['access_token'] = $accessToken->convertToJWT($this->pathToPrivateKey); + $redirectPayload['token_type'] = 'bearer'; + $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); + + return new Response\RedirectResponse($redirectUri->withFragment(http_build_query($redirectPayload))); + } + + // The user denied the client, redirect them back with an error + $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + + return $exception->generateHttpResponse(null, true); + } +} diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 00ffa149..1145e6ab 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\Event; @@ -20,7 +19,7 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Password grant class + * Password grant class. */ class PasswordGrant extends AbstractGrant { @@ -29,11 +28,6 @@ class PasswordGrant extends AbstractGrant */ private $userRepository; - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; - /** * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -43,13 +37,13 @@ class PasswordGrant extends AbstractGrant RefreshTokenRepositoryInterface $refreshTokenRepository ) { $this->userRepository = $userRepository; - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -58,14 +52,12 @@ class PasswordGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $user = $this->validateUser($request); + $user = $this->validateUser($request); $scopes = $this->validateScopes($request, $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); $refreshToken = $this->issueRefreshToken($accessToken); - $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); // Inject tokens into response $responseType->setAccessToken($accessToken); @@ -77,9 +69,9 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ protected function validateUser(ServerRequestInterface $request) { @@ -104,7 +96,7 @@ class PasswordGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index b43792ee..83ffe5ed 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -1,17 +1,17 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\Event; +use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -19,27 +19,22 @@ use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; /** - * Refresh token grant + * Refresh token grant. */ class RefreshTokenGrant extends AbstractGrant { - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; - /** * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository) { - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -47,13 +42,18 @@ class RefreshTokenGrant extends AbstractGrant \DateInterval $accessTokenTTL ) { // Validate request - $client = $this->validateClient($request); + $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($request, $client); + $scopes = $this->validateScopes($request, $client); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { - $scopes = $oldRefreshToken['scopes']; + $scopes = array_map(function ($scopeId) { + $scope = new ScopeEntity(); + $scope->setIdentifier($scopeId); + + return $scope; + }, $oldRefreshToken['scopes']); } else { // The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure // the request doesn't include any new scopes @@ -68,13 +68,13 @@ class RefreshTokenGrant extends AbstractGrant // Expire old tokens $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); - $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); + $this->getRefreshTokenRepository()->revokeRefreshToken($oldRefreshToken['refresh_token_id']); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); $refreshToken = $this->issueRefreshToken($accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + $this->getRefreshTokenRepository()->persistNewRefreshToken($refreshToken); // Inject tokens into response $responseType->setAccessToken($accessToken); @@ -87,9 +87,9 @@ class RefreshTokenGrant extends AbstractGrant * @param \Psr\Http\Message\ServerRequestInterface $request * @param string $clientId * - * @return array - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return array */ protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId) { @@ -120,7 +120,7 @@ class RefreshTokenGrant extends AbstractGrant throw OAuthServerException::invalidRefreshToken('Token has expired'); } - if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { + if ($this->getRefreshTokenRepository()->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { throw OAuthServerException::invalidRefreshToken('Token has been revoked'); } @@ -128,7 +128,7 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index f39351ff..d9e054d8 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; /** - * Access token interface + * Access token interface. */ interface AccessTokenRepositoryInterface extends RepositoryInterface { /** - * Persists a new access token to permanent storage + * Persists a new access token to permanent storage. * * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); /** - * Revoke an access token + * Revoke an access token. * * @param string $tokenId */ public function revokeAccessToken($tokenId); /** - * Check if the access token has been revoked + * Check if the access token has been revoked. * * @param string $tokenId * diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index a6742092..16c48742 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; /** - * Auth code storage interface + * Auth code storage interface. */ interface AuthCodeRepositoryInterface extends RepositoryInterface { /** - * Persists a new auth code to permanent storage + * Persists a new auth code to permanent storage. * * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity */ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); /** - * Revoke an auth code + * Revoke an auth code. * * @param string $codeId */ public function revokeAuthCode($codeId); /** - * Check if the auth code has been revoked + * Check if the auth code has been revoked. * * @param string $codeId * diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 3bec9452..0c7ebe4f 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -1,30 +1,27 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Client storage interface + * Client storage interface. */ interface ClientRepositoryInterface extends RepositoryInterface { /** - * Get a client + * Get a client. * - * @param string $grantType The grant type used - * @param string $clientIdentifier The client's identifier - * @param string|null $clientSecret The client's secret - * @param string|null $redirectUri The client's redirect URI + * @param string $clientIdentifier The client's identifier + * @param string $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function getClientEntity($grantType, $clientIdentifier, $clientSecret = null, $redirectUri = null); + public function getClientEntity($clientIdentifier, $grantType); } diff --git a/src/Repositories/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php index 833a0d7b..00e35a4c 100644 --- a/src/Repositories/MacTokenInterface.php +++ b/src/Repositories/MacTokenInterface.php @@ -1,25 +1,24 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Storage; use League\OAuth2\Server\Repositories\RepositoryInterface; /** - * MacTokenInterface + * MacTokenInterface. */ interface MacTokenInterface extends RepositoryInterface { /** - * Create a MAC key linked to an access token + * Create a MAC key linked to an access token. * * @param string $macKey * @param string $accessToken @@ -27,9 +26,9 @@ interface MacTokenInterface extends RepositoryInterface public function persistMacTokenEntity($macKey, $accessToken); /** - * Get a MAC key by access token + * Get a MAC key by access token. * - * @param string $accessToken + * @param string $accessToken * * @return string */ diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index 533351d8..d987ab22 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; /** - * Refresh token interface + * Refresh token interface. */ interface RefreshTokenRepositoryInterface extends RepositoryInterface { /** - * Create a new refresh token_name + * Create a new refresh token_name. * * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity */ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); /** - * Revoke the refresh token + * Revoke the refresh token. * * @param string $tokenId */ public function revokeRefreshToken($tokenId); /** - * Check if the refresh token has been revoked + * Check if the refresh token has been revoked. * * @param string $tokenId * diff --git a/src/Repositories/RepositoryInterface.php b/src/Repositories/RepositoryInterface.php index 030c116f..5273057c 100644 --- a/src/Repositories/RepositoryInterface.php +++ b/src/Repositories/RepositoryInterface.php @@ -1,18 +1,17 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Repository interface + * Repository interface. */ interface RepositoryInterface { diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 0b45efe9..5ac9aff8 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -1,23 +1,22 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Scope interface + * Scope interface. */ interface ScopeRepositoryInterface extends RepositoryInterface { /** - * Return information about a scope + * Return information about a scope. * * @param string $identifier The scope identifier * @param string $grantType The grant type used in the request diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index 5767a5ed..d93c85a7 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -5,7 +5,7 @@ namespace League\OAuth2\Server\Repositories; interface UserRepositoryInterface extends RepositoryInterface { /** - * Get a user entity + * Get a user entity. * * @param string $username * @param string $password diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 9605a463..bc218266 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index d1b88218..fdbe73b0 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -1,19 +1,16 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; -use Lcobucci\JWT\Builder; use Lcobucci\JWT\Parser; -use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -30,20 +27,11 @@ class BearerTokenResponse extends AbstractResponseType { $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp(); - $jwtAccessToken = (new Builder()) - ->setAudience($this->accessToken->getClient()->getIdentifier()) - ->setId($this->accessToken->getIdentifier(), true) - ->setIssuedAt(time()) - ->setNotBefore(time()) - ->setExpiration($expireDateTime) - ->setSubject($this->accessToken->getUserIdentifier()) - ->set('scopes', $this->accessToken->getScopes()) - ->sign(new Sha256(), new Key($this->pathToPrivateKey)) - ->getToken(); + $jwtAccessToken = $this->accessToken->convertToJWT($this->pathToPrivateKey); $responseParams = [ 'token_type' => 'Bearer', - 'expires_in' => $expireDateTime - (new \DateTime)->getTimestamp(), + 'expires_in' => $expireDateTime - (new \DateTime())->getTimestamp(), 'access_token' => (string) $jwtAccessToken, ]; diff --git a/src/ResponseTypes/MAC.php b/src/ResponseTypes/MAC.php index 48c2274f..598214d4 100644 --- a/src/ResponseTypes/MAC.php +++ b/src/ResponseTypes/MAC.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Util\SecureKey; @@ -16,7 +15,7 @@ use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; /** - * MAC Token Type + * MAC Token Type. */ class MAC extends AbstractTokenType implements TokenTypeInterface { @@ -29,11 +28,11 @@ class MAC extends AbstractTokenType implements TokenTypeInterface $this->server->getMacStorage()->create($macKey, $this->getParam('access_token')); $response = [ - 'access_token' => $this->getParam('access_token'), - 'token_type' => 'mac', - 'expires_in' => $this->getParam('expires_in'), - 'mac_key' => $macKey, - 'mac_algorithm' => 'hmac-sha-256', + 'access_token' => $this->getParam('access_token'), + 'token_type' => 'mac', + 'expires_in' => $this->getParam('expires_in'), + 'mac_key' => $macKey, + 'mac_algorithm' => 'hmac-sha-256', ]; return $response; @@ -121,9 +120,11 @@ class MAC extends AbstractTokenType implements TokenTypeInterface } /** - * Prevent timing attack - * @param string $knownString - * @param string $userString + * Prevent timing attack. + * + * @param string $knownString + * @param string $userString + * * @return bool */ private function hash_equals($knownString, $userString) diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 6524f049..34198eaf 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; @@ -30,7 +29,7 @@ interface ResponseTypeInterface /** * Determine the access token in the authorization header and append OAUth properties to the request - * as attributes + * as attributes. * * @param ServerRequestInterface $request * diff --git a/src/Server.php b/src/Server.php index 4e7799d3..248a5b7c 100644 --- a/src/Server.php +++ b/src/Server.php @@ -62,7 +62,7 @@ class Server implements EmitterAwareInterface private $scopeRepository; /** - * New server instance + * New server instance. * * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository @@ -88,7 +88,7 @@ class Server implements EmitterAwareInterface } /** - * Enable a grant type on the server + * Enable a grant type on the server. * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType * @param \DateInterval $accessTokenTTL @@ -108,13 +108,14 @@ class Server implements EmitterAwareInterface } /** - * Return an access token response + * Return an access token response. * * @param \Psr\Http\Message\ServerRequestInterface|null $request * @param \Psr\Http\Message\ResponseInterface|null $response * - * @return \Psr\Http\Message\ResponseInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ResponseInterface */ public function respondToRequest(ServerRequestInterface $request = null, ResponseInterface $response = null) { @@ -149,13 +150,13 @@ class Server implements EmitterAwareInterface } /** - * Determine the access token validity + * Determine the access token validity. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \Psr\Http\Message\ServerRequestInterface - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ServerRequestInterface */ public function validateRequest(ServerRequestInterface $request) { @@ -163,7 +164,7 @@ class Server implements EmitterAwareInterface } /** - * Get the token type that grants will return in the HTTP response + * Get the token type that grants will return in the HTTP response. * * @return ResponseTypeInterface */ diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php index 634cd80b..48659bde 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/Utils/KeyCrypt.php @@ -1,20 +1,19 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Utils; class KeyCrypt { /** - * Encrypt data with a private key + * Encrypt data with a private key. * * @param string $unencryptedData * @param string $pathToPrivateKey @@ -36,7 +35,9 @@ class KeyCrypt $chunk = substr($unencryptedData, 0, $chunkSize); $unencryptedData = substr($unencryptedData, $chunkSize); if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) { + // @codeCoverageIgnoreStart throw new \LogicException('Failed to encrypt data'); + // @codeCoverageIgnoreEnd } $output .= $encrypted; } @@ -46,7 +47,7 @@ class KeyCrypt } /** - * Decrypt data with a public key + * Decrypt data with a public key. * * @param string $encryptedData * @param string $pathToPublicKey @@ -72,7 +73,9 @@ class KeyCrypt $chunk = substr($encryptedData, 0, $chunkSize); $encryptedData = substr($encryptedData, $chunkSize); if (openssl_public_decrypt($chunk, $decrypted, $publicKey) === false) { + // @codeCoverageIgnoreStart throw new \LogicException('Failed to decrypt data'); + // @codeCoverageIgnoreEnd } $output .= $decrypted; } diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php deleted file mode 100644 index f5078bbf..00000000 --- a/src/Utils/SecureKey.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @copyright Copyright (c) 2013 PHP League of Extraordinary Packages - * @license http://mit-license.org/ - * @link http://github.com/php-loep/oauth2-server - */ - -namespace League\OAuth2\Server\Utils; - -use League\OAuth2\Server\Exception\OAuthServerException; - - -/** - * SecureKey class - */ -class SecureKey -{ - /** - * Generate a new unique code - * - * @param integer $len Length of the generated code - * - * @return string - * @throws \League\OAuth2\Server\Exception\OAuthServerException - */ - public static function generate($len = 40) - { - try { - $string = random_bytes($len); - } catch (\TypeError $e) { - // Well, it's an integer, so this IS unexpected. - throw OAuthServerException::serverError("An unexpected error has occurred"); - } catch (\Error $e) { - // This is also unexpected because 32 is a reasonable integer. - throw OAuthServerException::serverError("An unexpected error has occurred"); - } catch (\Exception $e) { - // If you get this message, the CSPRNG failed hard. - throw OAuthServerException::serverError("Could not generate a random string. Is our OS secure?"); - } - - return bin2hex($string); - } -} diff --git a/tests/unit/Bootstrap.php b/tests/Bootstrap.php similarity index 73% rename from tests/unit/Bootstrap.php rename to tests/Bootstrap.php index 4c9c8086..99c00e16 100644 --- a/tests/unit/Bootstrap.php +++ b/tests/Bootstrap.php @@ -1,5 +1,5 @@ wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php new file mode 100644 index 00000000..a2b764d2 --- /dev/null +++ b/tests/Grant/AbstractGrantTest.php @@ -0,0 +1,388 @@ +getMockForAbstractClass(AbstractGrant::class); + $grantMock->setPathToPrivateKey('./private.key'); + $grantMock->setPathToPublicKey('./public.key'); + $grantMock->setEmitter(new Emitter()); + } + + public function testValidateClientPublic() + { + $client = new ClientEntity(); + + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + ] + ); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $result = $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $this->assertEquals($client, $result); + } + + public function testValidateClientConfidential() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $client->setRedirectUri('http://foo/bar'); + + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'redirect_uri' => 'http://foo/bar', + ] + ); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $result = $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $this->assertEquals($client, $result); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientMissingClientId() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientMissingClientSecret() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientInvalidClientSecret() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'client_secret' => 'foo', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientInvalidRedirectUri() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar/foo', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientBadClient() + { + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true); + } + + public function testCanRespondToRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'grant_type' => 'foobar', + ]); + + $this->assertTrue($grantMock->canRespondToRequest($serverRequest)); + } + + public function testIssueRefreshToken() + { + $refreshTokenRepoMock = $this->getMock(RefreshTokenRepositoryInterface::class); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setRefreshTokenTTL(new \DateInterval('PT1M')); + $grantMock->setRefreshTokenRepository($refreshTokenRepoMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueRefreshTokenMethod = $abstractGrantReflection->getMethod('issueRefreshToken'); + $issueRefreshTokenMethod->setAccessible(true); + + $accessToken = new AccessTokenEntity(); + /** @var RefreshTokenEntityInterface $refreshToken */ + $refreshToken = $issueRefreshTokenMethod->invoke($grantMock, $accessToken); + $this->assertTrue($refreshToken instanceof RefreshTokenEntityInterface); + $this->assertFalse($refreshToken->isExpired()); + $this->assertEquals($accessToken, $refreshToken->getAccessToken()); + } + + public function testIssueAccessToken() + { + $accessTokenRepoMock = $this->getMock(AccessTokenRepositoryInterface::class); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setAccessTokenRepository($accessTokenRepoMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueAccessTokenMethod = $abstractGrantReflection->getMethod('issueAccessToken'); + $issueAccessTokenMethod->setAccessible(true); + + /** @var AccessTokenEntityInterface $accessToken */ + $accessToken = $issueAccessTokenMethod->invoke( + $grantMock, + new \DateInterval('PT1H'), + new ClientEntity(), + 123, + [new ScopeEntity()] + ); + $this->assertTrue($accessToken instanceof AccessTokenEntityInterface); + $this->assertFalse($accessToken->isExpired()); + } + + public function testIssueAuthCode() + { + $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setAuthCodeRepository($authCodeRepoMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode'); + $issueAuthCodeMethod->setAccessible(true); + + $this->assertTrue( + $issueAuthCodeMethod->invoke( + $grantMock, + new \DateInterval('PT1H'), + new ClientEntity(), + 123, + 'http://foo/bar', + [new ScopeEntity()] + ) instanceof AuthCodeEntityInterface + ); + } + + public function testGetCookieParameter() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $method = $abstractGrantReflection->getMethod('getCookieParameter'); + $method->setAccessible(true); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withCookieParams([ + 'foo' => 'bar', + ]); + + $this->assertEquals('bar', $method->invoke($grantMock, 'foo', $serverRequest)); + $this->assertEquals('foo', $method->invoke($grantMock, 'bar', $serverRequest, 'foo')); + } + + public function testGetQueryStringParameter() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $method = $abstractGrantReflection->getMethod('getQueryStringParameter'); + $method->setAccessible(true); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withQueryParams([ + 'foo' => 'bar', + ]); + + $this->assertEquals('bar', $method->invoke($grantMock, 'foo', $serverRequest)); + $this->assertEquals('foo', $method->invoke($grantMock, 'bar', $serverRequest, 'foo')); + } + + public function testValidateScopes() + { + $scope = new ScopeEntity(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setScopeRepository($scopeRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'scope' => 'basic ', + ] + ); + + $this->assertEquals([$scope], $grantMock->validateScopes($serverRequest, new ClientEntity())); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateScopesBadScope() + { + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn(null); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setScopeRepository($scopeRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'scope' => 'basic ', + ] + ); + + $grantMock->validateScopes($serverRequest, new ClientEntity()); + } + + public function testGenerateUniqueIdentifier() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $method = $abstractGrantReflection->getMethod('generateUniqueIdentifier'); + $method->setAccessible(true); + + $this->assertTrue(is_string($method->invoke($grantMock))); + } +} diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php new file mode 100644 index 00000000..1508329c --- /dev/null +++ b/tests/Grant/AuthCodeGrantTest.php @@ -0,0 +1,981 @@ +getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M'), + 'foo/bar.php', + 'foo/bar.php' + ); + + $this->assertEquals('authorization_code', $grant->getIdentifier()); + } + + public function testCanRespondToRequest() + { + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + ] + ); + + $this->assertTrue($grant->canRespondToRequest($request)); + } + + public function testRespondToAuthorizationRequest() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'state' => 'foobar', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + } + + public function testRespondToAuthorizationRequestUserDenied() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'state' => 'foobar', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'denied', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + $this->assertTrue(strstr($response->getHeader('location')[0], 'access_denied') !== false); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAuthorizationRequestMissingClientId() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } + + public function testRespondToAuthorizationRequestBadClient() + { + $client = null; + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getMessage(), 'Client authentication failed'); + } + } + + public function testRespondToAuthorizationRequestBadRedirectUri() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'sdfsdf', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getMessage(), 'Client authentication failed'); + } + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 7 + */ + public function testRespondToAuthorizationRequestBadCookie() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => 'blah', + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } + + public function testRespondToAuthorizationRequestTryLogin() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => null]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + } + + public function testRespondToAuthorizationRequestShowLoginForm() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = null; + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => null]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('content-type')[0], 'text/html') !== false); + $this->assertTrue(strstr($response->getBody()->getContents(), 'Incorrect username or password') !== false); + } + + public function testRespondToAuthorizationRequestShowAuthorizeForm() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [], + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); + } + + public function testRespondToAccessTokenRequest() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + /** @var StubResponseType $response */ + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAccessTokenRequestMissingRedirectUri() + { + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + ] + ); + + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAccessTokenRequestMissingCode() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } + + public function testRespondToAccessTokenRequestExpiredCode() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() - 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code has expired'); + } + } + + public function testRespondToAccessTokenRequestRevokedCode() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $authCodeRepositoryMock = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepositoryMock->method('isAuthCodeRevoked')->willReturn(true); + + $grant = new AuthCodeGrant( + $authCodeRepositoryMock, + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code has been revoked'); + } + } + + public function testRespondToAccessTokenRequestClientMismatch() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'bar', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code was not issued to this client'); + } + } + + public function testRespondToAccessTokenRequestBadCodeEncryption() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [], + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'sdfsfsd', + ] + ); + + try { + /* @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Cannot decrypt the authorization code'); + } + } +} diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php new file mode 100644 index 00000000..c67e889c --- /dev/null +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -0,0 +1,48 @@ +assertEquals('client_credentials', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $grant = new ClientCredentialsGrant(); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + } +} diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php new file mode 100644 index 00000000..e4f9e3a9 --- /dev/null +++ b/tests/Grant/PasswordGrantTest.php @@ -0,0 +1,165 @@ +getMock(UserRepositoryInterface::class); + $refreshTokenRepositoryMock = $this->getMock(RefreshTokenRepositoryInterface::class); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $this->assertEquals('password', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'foo', + 'password' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestMissingUsername() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestMissingPassword() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'alex', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestBadCredentials() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn(null); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'alex', + 'password' => 'whisky', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } +} diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php new file mode 100644 index 00000000..c9edebe2 --- /dev/null +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -0,0 +1,410 @@ +getMock(RefreshTokenRepositoryInterface::class); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $this->assertEquals('refresh_token', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + public function testRespondToReducedScopes() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $scope = new ScopeEntity(); + $scope->setIdentifier('foo'); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo', 'bar'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + 'scope' => 'foo', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 5 + */ + public function testRespondToUnexpectedScope() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $scope = new ScopeEntity(); + $scope->setIdentifier('foobar'); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo', 'bar'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + 'scope' => 'foobar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToRequestMissingOldToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestInvalidOldToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = 'foobar'; + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestClientMismatch() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'bar', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestExpiredToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() - 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestRevokedToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('isRefreshTokenRevoked')->willReturn(true); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } +} diff --git a/tests/ServerTest.php b/tests/ServerTest.php new file mode 100644 index 00000000..3f823a17 --- /dev/null +++ b/tests/ServerTest.php @@ -0,0 +1,56 @@ +getMock(ClientRepositoryInterface::class), + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + + $response = $server->respondToRequest(); + $this->assertTrue($response instanceof ResponseInterface); + $this->assertEquals(400, $response->getStatusCode()); + } + + public function testRespondToRequest() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + $clientRepository->method('getClientEntity')->willReturn(new ClientEntity()); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + + $_POST['grant_type'] = 'client_credentials'; + $_POST['client_id'] = 'foo'; + $_POST['client_secret'] = 'bar'; + $response = $server->respondToRequest(); + $this->assertEquals(200, $response->getStatusCode()); + } +} diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php new file mode 100644 index 00000000..22d093a0 --- /dev/null +++ b/tests/Stubs/StubResponseType.php @@ -0,0 +1,63 @@ +accessToken; + } + + public function getRefreshToken() + { + return $this->refreshToken; + } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + */ + public function setAccessToken(AccessTokenEntityInterface $accessToken) + { + $this->accessToken = $accessToken; + } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + */ + public function setRefreshToken(RefreshTokenEntityInterface $refreshToken) + { + $this->refreshToken = $refreshToken; + } + + /** + * @param ServerRequestInterface $request + * + * @return ServerRequestInterface + */ + public function determineAccessTokenInHeader(ServerRequestInterface $request) + { + // TODO: Implement determineAccessTokenInHeader() method. + } + + /** + * @param ResponseInterface $response + * + * @return ResponseInterface + */ + public function generateHttpResponse(ResponseInterface $response) + { + return new Response(); + } +} diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php new file mode 100644 index 00000000..5d102c77 --- /dev/null +++ b/tests/Stubs/UserEntity.php @@ -0,0 +1,13 @@ +assertNotEquals($payload, $encrypted); + $this->assertEquals($payload, $plainText); + } + + /** + * @expectedException \LogicException + */ + public function testBadPrivateKey() + { + KeyCrypt::encrypt('', 'file://' . __DIR__ . '/public.key'); + } + + /** + * @expectedException \LogicException + */ + public function testBadPublicKey() + { + KeyCrypt::decrypt('', 'file://' . __DIR__ . '/private.key'); + } +} diff --git a/tests/Utils/private.key b/tests/Utils/private.key new file mode 100644 index 00000000..1d6a3bf6 --- /dev/null +++ b/tests/Utils/private.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDOBcFjGUlo3BJ9zjwQLgAHn6Oy5Si0uB7MublTiPob8rWTiCE4 +weAFqzPoAB07vB0t0f8c1R8rmwHMD5ljWPBgJ8FewtwAUzprOBcau6DWukd/TKxX +WeVLAl/NZxijI+jR5QDBYLNBtj1G4LBVHMmINd3ryCycbf9ac3rcC8zhrQIDAQAB +AoGADfOJ0wIlXHp6rhZHLvlOezWuSjEGfqZxP3/cMvH1rerTrPfs+AD5AKlFTJKl +aCQm/bFYy0ULZVKL3pu30Wh2bo1nh/wLuLSI9Nz3O8jqAP3z0i07SoRoQmb8fRnn +dwoDFqnk3uGqcOenheSqheIgl9vdW/3avhD6nkMKZGxPYwECQQDoSj/xHogEzMqB +1Z2E5H/exeE9GQ7+dGITRR2MSgo9WvcKdRhGaQ44dsnTmqiZWAfqAPJjTQIIA/Cn +YRRTeBbNAkEA4w0iEvCIygGQOAnWuvVzlh+pxIB+BTeGkbiBG7nkYYc9b6B/Tw1B +GWGRddBr/FIfPvy1X2ip/TBpH+9bHnE2YQJBAIbZw/EYhmIy+UUSW9WwSUNsoOu1 +Rm0V53HEZ/jvaq5fxpa9j5AgoO7KlzROzp3m6wE/93cKV6mLkAO7ae9jAekCQQCf +B6DZIS6+RrAMACAt3SOzf8P6BYG/B7Ayusd7cw2ang4S9JiW9xKkw2kN2wj3t1F5 +XalwBTAjTdgj7ROmU+ehAkEAkOyXKONGBoVfaixRHgBP6jIBSSPbB2Aosi0QAURX +6GOY7wOS1pCSntTOBQxV7wVjqFwYAR10MSxFSNfpJ7RkzA== +-----END RSA PRIVATE KEY----- diff --git a/tests/Utils/public.key b/tests/Utils/public.key new file mode 100644 index 00000000..25010108 --- /dev/null +++ b/tests/Utils/public.key @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOBcFjGUlo3BJ9zjwQLgAHn6Oy +5Si0uB7MublTiPob8rWTiCE4weAFqzPoAB07vB0t0f8c1R8rmwHMD5ljWPBgJ8Fe +wtwAUzprOBcau6DWukd/TKxXWeVLAl/NZxijI+jR5QDBYLNBtj1G4LBVHMmINd3r +yCycbf9ac3rcC8zhrQIDAQAB +-----END PUBLIC KEY----- diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php deleted file mode 100644 index 243f9c85..00000000 --- a/tests/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ -wantTo('get an access token using the client credentials grant'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp', - 'client_secret' => 'abc123', - 'scope' => 'basic' - ] -); -$I->canSeeResponseCodeIs(200); -$I->canSeeResponseIsJson(); -$I->seeResponseJsonMatchesJsonPath('$.token_type'); -$I->seeResponseJsonMatchesJsonPath('$.expires_in'); -$I->seeResponseJsonMatchesJsonPath('$.access_token'); \ No newline at end of file diff --git a/tests/api/ClientCredentialsInvalidClientIdCept.php b/tests/api/ClientCredentialsInvalidClientIdCept.php deleted file mode 100644 index 97f9fce4..00000000 --- a/tests/api/ClientCredentialsInvalidClientIdCept.php +++ /dev/null @@ -1,17 +0,0 @@ -wantTo('get an access token using the client credentials grant, invalid client id'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp-wrong', - 'client_secret' => 'foobar' - ] -); -$I->canSeeResponseCodeIs(401); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_client', - 'message' => 'Client authentication failed.' -]); diff --git a/tests/api/ClientCredentialsInvalidClientSecretCept.php b/tests/api/ClientCredentialsInvalidClientSecretCept.php deleted file mode 100644 index fe4f88fc..00000000 --- a/tests/api/ClientCredentialsInvalidClientSecretCept.php +++ /dev/null @@ -1,17 +0,0 @@ -wantTo('get an access token using the client credentials grant, invalid client secret'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp', - 'client_secret' => 'foobar' - ] -); -$I->canSeeResponseCodeIs(401); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_client', - 'message' => 'Client authentication failed.' -]); diff --git a/tests/api/ClientCredentialsMissingClientIdCept.php b/tests/api/ClientCredentialsMissingClientIdCept.php deleted file mode 100644 index 68135cdb..00000000 --- a/tests/api/ClientCredentialsMissingClientIdCept.php +++ /dev/null @@ -1,15 +0,0 @@ -wantTo('get an access token using the client credentials grant, missing client id'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials' - ] -); -$I->canSeeResponseCodeIs(400); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_request', - 'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_id" parameter.' -]); diff --git a/tests/api/ClientCredentialsMissingClientSecretCept.php b/tests/api/ClientCredentialsMissingClientSecretCept.php deleted file mode 100644 index 369e22d6..00000000 --- a/tests/api/ClientCredentialsMissingClientSecretCept.php +++ /dev/null @@ -1,16 +0,0 @@ -wantTo('get an access token using the client credentials grant, missing client secret'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp' - ] -); -$I->canSeeResponseCodeIs(400); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_request', - 'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_secret" parameter.' -]); diff --git a/tests/api/_bootstrap.php b/tests/api/_bootstrap.php deleted file mode 100644 index 8a885558..00000000 --- a/tests/api/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ -addEventListener('event.name', function () use ($var) { - $var++; - $this->assertSame(1, $var); - }); - $server->getEventEmitter()->emit('event.name'); - $this->assertTrue($server->getRequest() instanceof \Symfony\Component\HttpFoundation\Request); - $this->assertTrue($server->getEventEmitter() instanceof \League\Event\Emitter); - - $server2 = new StubAbstractServer(); - $server2->setRequest((new \Symfony\Component\HttpFoundation\Request())); - $server2->setEventEmitter(1); - $this->assertTrue($server2->getRequest() instanceof \Symfony\Component\HttpFoundation\Request); - } -} diff --git a/tests/unit/AuthorizationServerTest.php b/tests/unit/AuthorizationServerTest.php deleted file mode 100644 index 10a21686..00000000 --- a/tests/unit/AuthorizationServerTest.php +++ /dev/null @@ -1,82 +0,0 @@ -requireScopeParam(true); - $server->requireStateParam(true); - $server->setDefaultScope('foobar'); - $server->setScopeDelimiter(','); - $server->setAccessTokenTTL(1); - - $grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface'); - $grant->shouldReceive('getIdentifier')->andReturn('foobar'); - $grant->shouldReceive('getResponseType')->andReturn('foobar'); - $grant->shouldReceive('setAuthorizationServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->addGrantType($grant); - $server->setScopeStorage($scopeStorage); - - $this->assertTrue($server->hasGrantType('foobar')); - $this->assertTrue($server->getGrantType('foobar') instanceof GrantTypeInterface); - $this->assertSame($server->getResponseTypes(), ['foobar']); - $this->assertTrue($server->scopeParamRequired()); - $this->assertTrue($server->stateParamRequired()); - $this->assertTrue($server->getScopeStorage() instanceof ScopeInterface); - $this->assertEquals('foobar', $server->getDefaultScope()); - $this->assertEquals(',', $server->getScopeDelimiter()); - $this->assertEquals(1, $server->getAccessTokenTTL()); - } - - public function testInvalidGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidGrantException'); - $server = new AuthorizationServer(); - $server->getGrantType('foobar'); - } - - public function testIssueAccessToken() - { - $grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface'); - $grant->shouldReceive('getIdentifier')->andReturn('foobar'); - $grant->shouldReceive('getResponseType')->andReturn('foobar'); - $grant->shouldReceive('setAuthorizationServer'); - $grant->shouldReceive('completeFlow')->andReturn(true); - - $_POST['grant_type'] = 'foobar'; - - $server = new AuthorizationServer(); - $server->addGrantType($grant); - - $this->assertTrue($server->issueAccessToken()); - } - - public function testIssueAccessTokenEmptyGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - $server = new AuthorizationServer(); - $this->assertTrue($server->issueAccessToken()); - } - - public function testIssueAccessTokenInvalidGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\UnsupportedGrantTypeException'); - - $_POST['grant_type'] = 'foobar'; - - $server = new AuthorizationServer(); - $this->assertTrue($server->issueAccessToken()); - } -} diff --git a/tests/unit/Entity/AbstractTokenEntityTest.php b/tests/unit/Entity/AbstractTokenEntityTest.php deleted file mode 100644 index 24428085..00000000 --- a/tests/unit/Entity/AbstractTokenEntityTest.php +++ /dev/null @@ -1,116 +0,0 @@ -setId('foobar'); - $entity->setExpireTime($time); - $entity->setSession((new SessionEntity($server))); - $entity->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $this->assertEquals('foobar', $entity->getId()); - $this->assertEquals($time, $entity->getExpireTime()); - // $this->assertTrue($entity->getSession() instanceof SessionEntity); - // $this->assertTrue($entity->hasScope('foo')); - - // $result = $entity->getScopes(); - // $this->assertTrue(isset($result['foo'])); - } - - /*public function testGetSession() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setSessionStorage'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getStorage')->andReturn($sessionStorage); - - $server->setSessionStorage($sessionStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertTrue($entity->getSession() instanceof SessionEntity); - }*/ - - /*public function testGetScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $accessTokenStorage->shouldReceive('setServer'); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertEquals($entity->getScopes(), []); - }*/ - - /*public function testHasScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $accessTokenStorage''>shouldReceive('setServer'); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertFalse($entity->hasScope('foo')); - }*/ - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new StubAbstractTokenEntity($server); - $reflectedEntity = new \ReflectionClass('LeagueTests\Stubs\StubAbstractTokenEntity'); - $method = $reflectedEntity->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1', 'description' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2', 'description' => 'bar']), - ]; - - $result = $method->invokeArgs($entity, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function test__toString() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new StubAbstractTokenEntity($server); - $this->assertEquals('', (string) $entity); - $entity->setId('foobar'); - $this->assertEquals('foobar', (string) $entity); - } -} diff --git a/tests/unit/Entity/AccessTokenEntityTest.php b/tests/unit/Entity/AccessTokenEntityTest.php deleted file mode 100644 index 6f2a617e..00000000 --- a/tests/unit/Entity/AccessTokenEntityTest.php +++ /dev/null @@ -1,59 +0,0 @@ -shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - $server->setSessionStorage($sessionStorage); - - $entity = new AccessTokenEntity($server); - $this->assertTrue($entity->save() instanceof AccessTokenEntity); - } - - public function testExpire() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $server->shouldReceive('setAccessTokenStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('setServer'); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new AccessTokenEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/AuthCodeEntityTest.php b/tests/unit/Entity/AuthCodeEntityTest.php deleted file mode 100644 index 5b7fc089..00000000 --- a/tests/unit/Entity/AuthCodeEntityTest.php +++ /dev/null @@ -1,73 +0,0 @@ -setRedirectUri('http://foo/bar'); - $code->setId('foobar'); - $code->setSession($session); - - $this->assertEquals('http://foo/bar', $code->getRedirectUri()); - $this->assertEquals('http://foo/bar?code=foobar', $code->generateRedirectUri()); - $this->assertTrue($code->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setAuthCodeStorage'); - $server->shouldReceive('setSessionStorage'); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('create'); - $authCodeStorage->shouldReceive('associateScope'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getAuthCodeStorage')->andReturn($authCodeStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $server->setAuthCodeStorage($authCodeStorage); - $server->setSessionStorage($sessionStorage); - - $entity = new AuthCodeEntity($server); - $this->assertTrue($entity->save() instanceof AuthCodeEntity); - } - - public function testExpire() - { - $server = new AuthorizationServer(); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('setServer'); - - $server->setAuthCodeStorage($authCodeStorage); - - $entity = new AuthCodeEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/ClientEntityTest.php b/tests/unit/Entity/ClientEntityTest.php deleted file mode 100644 index 9bb13c7d..00000000 --- a/tests/unit/Entity/ClientEntityTest.php +++ /dev/null @@ -1,25 +0,0 @@ -hydrate([ - 'id' => 'foobar', - 'secret' => 'barfoo', - 'name' => 'Test Client', - 'redirectUri' => 'http://foo/bar', - ]); - - $this->assertEquals('foobar', $client->getId()); - $this->assertEquals('barfoo', $client->getSecret()); - $this->assertEquals('Test Client', $client->getName()); - $this->assertEquals('http://foo/bar', $client->getRedirectUri()); - } -} diff --git a/tests/unit/Entity/RefreshTokenEntityTest.php b/tests/unit/Entity/RefreshTokenEntityTest.php deleted file mode 100644 index f2b05cf7..00000000 --- a/tests/unit/Entity/RefreshTokenEntityTest.php +++ /dev/null @@ -1,94 +0,0 @@ -setAccessTokenId('foobar'); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessTokenId'); - $accessTokenProperty->setAccessible(true); - - $this->assertSame($accessTokenProperty->getValue($entity), 'foobar'); - } - - public function testSetAccessToken() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $entity = new RefreshTokenEntity($server); - $entity->setAccessToken((new AccessTokenEntity($server))); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessTokenEntity'); - $accessTokenProperty->setAccessible(true); - - $this->assertTrue($accessTokenProperty->getValue($entity) instanceof AccessTokenEntity); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setRefreshTokenStorage'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->shouldReceive('getRefreshTokenStorage')->andReturn($refreshTokenStorage); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('foobar') - ); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $entity = new RefreshTokenEntity($server); - $this->assertSame(null, $entity->save()); - } - - public function testExpire() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setRefreshTokenStorage'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('setServer'); - - $server->shouldReceive('getRefreshTokenStorage')->andReturn($refreshTokenStorage); - - $server->setRefreshTokenStorage($refreshTokenStorage); - - $entity = new RefreshTokenEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/ScopeEntityTest.php b/tests/unit/Entity/ScopeEntityTest.php deleted file mode 100644 index 3fec4fe1..00000000 --- a/tests/unit/Entity/ScopeEntityTest.php +++ /dev/null @@ -1,23 +0,0 @@ -hydrate([ - 'id' => 'foobar', - 'description' => 'barfoo', - ]); - - $this->assertEquals('foobar', $scope->getId()); - $this->assertEquals('barfoo', $scope->getDescription()); - - $this->assertTrue(is_array($scope->jsonSerialize())); - } -} diff --git a/tests/unit/Entity/SessionEntityTest.php b/tests/unit/Entity/SessionEntityTest.php deleted file mode 100644 index 5ca26a75..00000000 --- a/tests/unit/Entity/SessionEntityTest.php +++ /dev/null @@ -1,154 +0,0 @@ -shouldReceive('emit'); - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setEventEmitter'); - $server->shouldReceive('getEventEmitter')->andReturn($emitter); - $server->setEventEmitter($emitter); - - $entity = new SessionEntity($server); - $entity->setId('foobar'); - $entity->setOwner('user', 123); - $entity->associateAccessToken((new AccessTokenEntity($server))); - $entity->associateRefreshToken((new RefreshTokenEntity($server))); - $entity->associateClient((new ClientEntity($server))); - $entity->associateScope( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - // $entity->associateAuthCode((new AuthCode($server))); - - $this->assertEquals('foobar', $entity->getId()); - $this->assertEquals('user', $entity->getOwnerType()); - $this->assertEquals(123, $entity->getOwnerId()); - $this->assertTrue($entity->getClient() instanceof ClientEntity); - $this->assertTrue($entity->hasScope('foo')); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessToken'); - $accessTokenProperty->setAccessible(true); - $refreshTokenProperty = $reflector->getProperty('refreshToken'); - $refreshTokenProperty->setAccessible(true); - - $this->assertTrue($accessTokenProperty->getValue($entity) instanceof AccessTokenEntity); - $this->assertTrue($refreshTokenProperty->getValue($entity) instanceof RefreshTokenEntity); - // $this->assertTrue($reader($entity, 'authCode') instanceof AuthCode); - } - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new SessionEntity($server); - $reflectedEntity = new \ReflectionClass('League\OAuth2\Server\Entity\SessionEntity'); - $method = $reflectedEntity->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2']), - ]; - - $result = $method->invokeArgs($entity, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function testGetScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $sessionStorage->shouldReceive('setServer'); - $server->setSessionStorage($sessionStorage); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $entity = new SessionEntity($server); - $this->assertEquals($entity->getScopes(), []); - } - - public function testHasScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $sessionStorage->shouldReceive('setServer'); - $server->setSessionStorage($sessionStorage); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $entity = new SessionEntity($server); - $this->assertFalse($entity->hasScope('foo')); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setSessionStorage'); - $server->shouldReceive('setClientStorage'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'foo']) - ); - $clientStorage->shouldReceive('setServer'); - - $server->shouldReceive('getClientStorage')->andReturn($clientStorage); - - $server->setSessionStorage($sessionStorage); - $server->setClientStorage($clientStorage); - - $entity = new SessionEntity($server); - $this->assertEquals(null, $entity->save()); - } -} diff --git a/tests/unit/Exception/OAuthExceptionTest.php b/tests/unit/Exception/OAuthExceptionTest.php deleted file mode 100644 index 273ed374..00000000 --- a/tests/unit/Exception/OAuthExceptionTest.php +++ /dev/null @@ -1,34 +0,0 @@ -httpStatusCode = 400; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 400 Bad Request']); - - $exception->httpStatusCode = 401; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 401 Unauthorized']); - - $exception->httpStatusCode = 500; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 500 Internal Server Error']); - - $exception->httpStatusCode = 501; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 501 Not Implemented']); - } - - public function testShouldRedirect() - { - $exception = new OAuthException(); - $exception->redirectUri = 'http://example.com/'; - $exception->errorType = 'Error'; - $this->assertTrue($exception->shouldRedirect()); - $this->assertEquals('http://example.com/?error=Error&message=An+error+occured', $exception->getRedirectUri()); - } -} diff --git a/tests/unit/Grant/AbstractGrantTest.php b/tests/unit/Grant/AbstractGrantTest.php deleted file mode 100644 index 8a57b61b..00000000 --- a/tests/unit/Grant/AbstractGrantTest.php +++ /dev/null @@ -1,160 +0,0 @@ -setIdentifier('foobar'); - $grant->setAccessTokenTTL(300); - $grant->setAuthorizationServer($server); - - $this->assertEquals('foobar', $grant->getIdentifier()); - $this->assertEquals('foobar', $grant->getResponseType()); - $this->assertEquals(300, $grant->getAccessTokenTTL()); - $this->assertTrue($grant->getAuthorizationServer() instanceof AuthorizationServer); - } - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $grant = new StubAbstractGrant(); - $reflectedGrant = new \ReflectionClass('LeagueTests\Stubs\StubAbstractGrant'); - $method = $reflectedGrant->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1', 'description' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2', 'description' => 'bar']), - ]; - - $result = $method->invokeArgs($grant, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function testValidateScopes() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $this->assertEquals( - [ - 'foo' => (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ], - $grant->validateScopes('foo', $client) - ); - } - - public function testValidateScopesMissingScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new AuthorizationServer(); - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } - - public function testValidateScopesInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server = new AuthorizationServer(); - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes('blah', $client); - } - - public function testValidateScopesDefaultScope() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - $server->setScopeStorage($scopeStorage); - - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - $server->setDefaultScope('foo'); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } - - public function testValidateScopesDefaultScopeArray() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - $server->setScopeStorage($scopeStorage); - - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - $server->setDefaultScope(['foo', 'bar']); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } -} diff --git a/tests/unit/Grant/AuthCodeGrantTest.php b/tests/unit/Grant/AuthCodeGrantTest.php deleted file mode 100644 index 72a564d4..00000000 --- a/tests/unit/Grant/AuthCodeGrantTest.php +++ /dev/null @@ -1,696 +0,0 @@ -setAuthTokenTTL(100); - - $class = new \ReflectionClass($grant); - $property = $class->getProperty('authTokenTTL'); - $property->setAccessible(true); - $this->assertEquals(100, $property->getValue($grant)); - } - - public function testCheckAuthoriseParamsMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = []; - $server = new AuthorizationServer(); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingRedirectUri() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $server = new AuthorizationServer(); - $_GET = [ - 'client_id' => 'testapp', - ]; - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'response_type' => 'code', - ]; - $server = new AuthorizationServer(); - - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingStateParam() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - $server->requireStateParam(true); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingResponseType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidResponseType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\UnsupportedResponseTypeException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'response_type' => 'foobar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_GET = [ - 'response_type' => 'code', - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParams() - { - $_GET = [ - 'response_type' => 'code', - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - - $result = $grant->checkAuthorizeParams(); - - $this->assertTrue($result['client'] instanceof ClientEntity); - $this->assertTrue($result['redirect_uri'] === $_GET['redirect_uri']); - $this->assertTrue($result['state'] === null); - $this->assertTrue($result['response_type'] === 'code'); - $this->assertTrue($result['scopes']['foo'] instanceof ScopeEntity); - } - - public function testNewAuthoriseRequest() - { - $server = new AuthorizationServer(); - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - $scope = (new ScopeEntity($server))->hydrate(['id' => 'foo']); - - $grant = new AuthCodeGrant(); - $server->addGrantType($grant); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([$scope]); - $sessionStorage->shouldReceive('associateScope'); - $server->setSessionStorage($sessionStorage); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - $authCodeStorage->shouldReceive('create'); - $authCodeStorage->shouldReceive('associateScope'); - $server->setAuthCodeStorage($authCodeStorage); - - $grant->newAuthorizeRequest('user', 123, [ - 'client' => $client, - 'redirect_uri' => 'http://foo/bar', - 'scopes' => [$scope], - 'state' => 'foobar' - ]); - } - - public function testCompleteFlowMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'authorization_code'; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingRedirectUri() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowExpiredCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setExpireTime(time() - 300)->setRedirectUri('http://foo/bar') - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowRedirectUriMismatch() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setExpireTime(time() + 300)->setRedirectUri('http://fail/face') - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setRedirectUri('http://foo/bar')->setExpireTime(time() + 300) - ); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowWithRefreshToken() - { - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - $rtgrant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setRedirectUri('http://foo/bar')->setExpireTime(time() + 300) - ); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $server->addGrantType($rtgrant); - $server->issueAccessToken(); - } -} diff --git a/tests/unit/Grant/ClientCredentialsGrantTest.php b/tests/unit/Grant/ClientCredentialsGrantTest.php deleted file mode 100644 index 8e5643f5..00000000 --- a/tests/unit/Grant/ClientCredentialsGrantTest.php +++ /dev/null @@ -1,251 +0,0 @@ -setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'client_credentials'; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowNoScopes() - { - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - // $scopeStorage->shouldReceive('get')->andReturn( - // // (new ScopeEntity($server))->hydrate(['id' => 'foo']) - // ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testClientNotAuthorizedToUseGrant() - { - $this->setExpectedException('\League\OAuth2\Server\Exception\UnauthorizedClientException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andThrow( - new \League\OAuth2\Server\Exception\UnauthorizedClientException() - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } -} diff --git a/tests/unit/Grant/PasswordGrantTest.php b/tests/unit/Grant/PasswordGrantTest.php deleted file mode 100644 index e54ca479..00000000 --- a/tests/unit/Grant/PasswordGrantTest.php +++ /dev/null @@ -1,479 +0,0 @@ -setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'password'; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoUsername() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoPassword() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoCallable() - { - $this->setExpectedException('League\OAuth2\Server\Exception\ServerErrorException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - 'password' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - 'password' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowNoScopes() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->requireScopeParam(true); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidCredentials() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidCredentialsException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return false; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } - - public function testCompleteFlowRefreshToken() - { - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->addGrantType(new RefreshTokenGrant()); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - // $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } -} diff --git a/tests/unit/Grant/RefreshTokenGrantTest.php b/tests/unit/Grant/RefreshTokenGrantTest.php deleted file mode 100644 index bd5ae5ab..00000000 --- a/tests/unit/Grant/RefreshTokenGrantTest.php +++ /dev/null @@ -1,501 +0,0 @@ -setRefreshTokenTTL(86400); - - $property = new \ReflectionProperty($grant, 'refreshTokenTTL'); - $property->setAccessible(true); - - $this->assertEquals(86400, $property->getValue($grant)); - } - - public function testCompleteFlowMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'refresh_token'; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->requireScopeParam(true); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRefreshException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'meh', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('get'); - $refreshTokenStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - $server->requireScopeParam(true); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowExistingScopes() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } - - public function testCompleteFlowRequestScopes() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(isset($response['access_token'])); - $this->assertTrue(isset($response['refresh_token'])); - $this->assertTrue(isset($response['token_type'])); - $this->assertTrue(isset($response['expires_in'])); - } - - public function testCompleteFlowExpiredRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRefreshException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server)) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowRequestScopesInvalid() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'blah', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'blah']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $server->issueAccessToken(); - } - - public function testCompleteFlowRotateRefreshToken() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setId('refresh_token')->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - - $response = $server->issueAccessToken(); - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - $this->assertNotEquals($response['refresh_token'], $_POST['refresh_token']); - - $grant->setRefreshTokenRotation(false); - $response = $server->issueAccessToken(); - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - $this->assertEquals($response['refresh_token'], $_POST['refresh_token']); - } -} diff --git a/tests/unit/ResourceServerTest.php b/tests/unit/ResourceServerTest.php deleted file mode 100644 index 8855abad..00000000 --- a/tests/unit/ResourceServerTest.php +++ /dev/null @@ -1,226 +0,0 @@ -shouldReceive('setServer'); - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - return $server; - } - - public function testGetSet() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - } - - public function testDetermineAccessTokenMissingToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn(false); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'HTTP_AUTHORIZATION' => 'Bearer', - ]); - $server->setRequest($request); - - $reflector = new \ReflectionClass($server); - $method = $reflector->getMethod('determineAccessToken'); - $method->setAccessible(true); - - $method->invoke($server); - } - - public function testIsValidNotValid() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn(false); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $this->setExpectedException('League\OAuth2\Server\Exception\AccessDeniedException'); - $server->isValidRequest(false, 'foobar'); - } - - public function testIsValid() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $server->setIdKey('at'); - - $server->addEventListener('session.owner', function ($event) { - $this->assertTrue($event->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - }); - - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('abcdef')->setExpireTime(time() + 300) - ); - - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'bar']), - ]); - - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar')->setOwner('user', 123) - ); - - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'Authorization' => 'Bearer abcdef', - ]); - $server->setRequest($request); - - $this->assertTrue($server->isValidRequest()); - $this->assertEquals('abcdef', $server->getAccessToken()); - } - - /** - * @expectedException League\OAuth2\Server\Exception\AccessDeniedException - */ - public function testIsValidExpiredToken() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $server->setIdKey('at'); - - $server->addEventListener('session.owner', function ($event) { - $this->assertTrue($event->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - }); - - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('abcdef')->setExpireTime(time() - 300) - ); - - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'bar']), - ]); - - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar')->setOwner('user', 123) - ); - - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'Authorization' => 'Bearer abcdef', - ]); - $server->setRequest($request); - - $server->isValidRequest(); - } -} diff --git a/tests/unit/Storage/AbstractStorageTest.php b/tests/unit/Storage/AbstractStorageTest.php deleted file mode 100644 index 30312cb7..00000000 --- a/tests/unit/Storage/AbstractStorageTest.php +++ /dev/null @@ -1,23 +0,0 @@ -getMethod('setServer'); - $setMethod->setAccessible(true); - $setMethod->invokeArgs($storage, [new StubAbstractServer()]); - $getMethod = $reflector->getMethod('getServer'); - $getMethod->setAccessible(true); - - $this->assertTrue($getMethod->invoke($storage) instanceof StubAbstractServer); - } -} diff --git a/tests/unit/Stubs/StubAbstractGrant.php b/tests/unit/Stubs/StubAbstractGrant.php deleted file mode 100644 index d58fb56e..00000000 --- a/tests/unit/Stubs/StubAbstractGrant.php +++ /dev/null @@ -1,18 +0,0 @@ -server; - } -} diff --git a/tests/unit/Stubs/StubAbstractServer.php b/tests/unit/Stubs/StubAbstractServer.php deleted file mode 100644 index 9254d80d..00000000 --- a/tests/unit/Stubs/StubAbstractServer.php +++ /dev/null @@ -1,8 +0,0 @@ -shouldReceive('create'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $accessToken = new AccessTokenEntity($server); - $accessToken->setId(uniqid()); - $accessToken->setExpireTime(time()); - - $tokenType->setParam('access_token', $accessToken->getId()); - $tokenType->setParam('expires_in', 3600); - - $response = $tokenType->generateResponse(); - - $this->assertEquals($accessToken->getId(), $response['access_token']); - $this->assertEquals('mac', $response['token_type']); - $this->assertEquals(3600, $response['expires_in']); - $this->assertEquals('hmac-sha-256', $response['mac_algorithm']); - $this->assertArrayHasKey('mac_key', $response); - } - - public function testDetermineAccessTokenInHeaderValid() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time(); - - $request = Request::createFromGlobals(); - $calculatedSignatureParts = [ - $ts, - 'foo', - strtoupper($request->getMethod()), - $request->getUri(), - $request->getHost(), - $request->getPort(), - 'ext' - ]; - $calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), 'abcdef')); - - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, $calculatedSignature)); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals('foo', $response); - } - - public function testDetermineAccessTokenInHeaderMissingHeader() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMissingAuthMac() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', ''); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderInvalidParam() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', 'MAC '); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMismatchTimestamp() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time() - 100; - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo')); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMissingMacKey() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn(null); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time(); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo')); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals(null, $response); - } -} diff --git a/tests/unit/util/RedirectUriTest.php b/tests/unit/util/RedirectUriTest.php deleted file mode 100644 index 6b677404..00000000 --- a/tests/unit/util/RedirectUriTest.php +++ /dev/null @@ -1,19 +0,0 @@ - 'bar']); - $v2 = RedirectUri::make('https://foobar/', ['foo' => 'bar'], '#'); - $v3 = RedirectUri::make('https://foobar/', ['foo' => 'bar', 'bar' => 'foo']); - - $this->assertEquals('https://foobar/?foo=bar', $v1); - $this->assertEquals('https://foobar/#foo=bar', $v2); - $this->assertEquals('https://foobar/?foo=bar&bar=foo', $v3); - } -} diff --git a/tests/unit/util/SecureKeyTest.php b/tests/unit/util/SecureKeyTest.php deleted file mode 100644 index 394226f5..00000000 --- a/tests/unit/util/SecureKeyTest.php +++ /dev/null @@ -1,35 +0,0 @@ -assertEquals(40, strlen($v1)); - $this->assertTrue($v1 !== $v2); - $this->assertEquals(50, strlen($v3)); - } - - public function testGenerateWithDifferentAlgorithm() - { - $algorithm = $this->getMock('League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface'); - - $result = 'dasdsdsaads'; - $algorithm - ->expects($this->once()) - ->method('generate') - ->with(11) - ->will($this->returnValue($result)); - - SecureKey::setAlgorithm($algorithm); - $this->assertSame($algorithm, SecureKey::getAlgorithm()); - $this->assertEquals($result, SecureKey::generate(11)); - } -}